Index: deps/glpk/AUTHORS
===================================================================
--- deps/glpk/AUTHORS	(revision 9)
+++ deps/glpk/AUTHORS	(revision 9)
@@ -0,0 +1,33 @@
+The GLPK package was developed and programmed by Andrew Makhorin,
+Department for Applied Informatics, Moscow Aviation Institute, Moscow,
+Russia.
+
+E-mail:         <mao@gnu.org>
+
+Paper mail:     125871, Russia, Moscow, Volokolamskoye sh., 4,
+                Moscow Aviation Institute, Andrew O. Makhorin
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.2 (MingW32)
+
+mQGiBD8UdT8RBAC6yWYxoa1b7U973J0jBuQpgZnhXlGJJpMZgAW9efDBD17vhkJm
+hPVOQBKRUeOOLcW3/a7NMoNLMdmF1Rgz1FPVy3RgBDsYj4Sp4RBCsX/o0xXh+jxe
+gncr4bdN0Ruk03pezVtLi9oYygdxfI51SsjZ2vwYP6BhMwv+xrIgcnc4qwCgoCit
+26mTd0FoGOmsQuipo6X5LaUD/1l7NqFIjiGdWthyG3TqsiK5Ew7xF3fLEABXKPjb
+PMRTMucX8XXHmW8RUD1vP1uGDnEn6s+fjc3/RtaqKjqGMdLt4XgHQkImaVguNpSS
+IxN3LaK600BgAbwSd1bomRqWNlczAM7469VvGG9ASpCBveUUrqwerHZcUbvngL62
+pIcqA/41dO0xYrOTqMRhuguYMgHL2xbwB2Aj2TqRwBm697DIS25B9nE+8UsbjGRx
+q3EmeuHeZ5kN5RbESXkGUB8whIcYxvH16HRNmM1ZjmFoBVL2Z6S2gpa2ZUqsq7BZ
+s+hriElm3dfOQCt79/o852uKWu5bSjw2yiemVA2T8tG4OoN6DrQjQW5kcmV3IE1h
+a2hvcmluIDxtYW9AbWFpMi5yY25ldC5ydT6IWwQTEQIAGwUCPxR1PwYLCQgHAwID
+FQIDAxYCAQIeAQIXgAAKCRDRe/IwWYHoGKpHAJ44MmzWKr8OiTc0Bb6/RD56aekp
+3wCdGznQMCfWFkehQPbeNaB5yFIs+8a5AQ0EPxR1UBAEAO3U3H5M0iYv06C4kKty
+6ReWyYH4CzMAfp2lPVUKzRSjPtoAJ6SkrBSKMT+U+DahxZ4K4HbinvHq3uvlwWax
+xw0wKxJl4oY6EGE1Jqn3B//Ak47RaNMnrs9V739WT1YNRpQvh4wOCeMekBzksf43
+hm4dSV4PMQkLmrEeG2+BYaZnAAMFA/4tVHhjGRkxzcTcfHCB+Yo3PXeIQMuIs00c
+VKCrNReLni/3BWZC0w9tFzZSdz+URXefPWDGuAC16vLCVOD06NcIQGutPe189dUn
+Kf9Bl6qc9DyWsxSTdF/PbLqcLfEe9g7fHhIwdY+w/hSq2n3NEURMzHiMT1U3CvHd
+As5IzV/yD4hGBBgRAgAGBQI/FHVQAAoJENF78jBZgegYRZEAmwReJkMSrbs0EQs2
+wjyTCMd5KDh3AKCR2/RvVad9RT3ShYnUiPPYTL2/Nw==
+=OfLQ
+-----END PGP PUBLIC KEY BLOCK-----
Index: deps/glpk/COPYING
===================================================================
--- deps/glpk/COPYING	(revision 9)
+++ deps/glpk/COPYING	(revision 9)
@@ -0,0 +1,676 @@
+
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
Index: deps/glpk/ChangeLog
===================================================================
--- deps/glpk/ChangeLog	(revision 9)
+++ deps/glpk/ChangeLog	(revision 9)
@@ -0,0 +1,2432 @@
+Fri Sep 09 12:00:00 2011 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.47 (32:0:32) has been released
+
+        * src/glpapi20.c
+        New API routine glp_infeas1 to solve 0-1 feasibility problem
+        was added and documented (see doc/cnfsat.pdf).
+
+        * src/glpnpp06.c
+        Some new preprocessor routines for SAT-CNF encoding, which are
+        used by the routine glp_intfeas1, were added.
+
+        * src/glpnpp.h
+        The header was modified due to additions.
+
+        * src/glpapi21.c
+        The glpsol solver was modified to bypass model postprocessing
+        if the solution reported is neither optimal nor feasible.
+
+        * src/glpapi21.c
+        New glpsol options (--minisat and --objbnd) were added.
+
+        * examples/pbn/*.*
+        The paint-by-numbers puzzle model (pbn.mod) was modified to
+        print solution in PostScript format and to check for multiple
+        solutions. Some benchmark examples from <webpbn.com> encoded
+        in MathProg were included in the distribution. For more details
+        see examples/pbn/README and examples/pbn/pbn.pdf.
+
+        * examples/Makefile.am
+        A minor bug was fixed to correctly build glpk in a separate
+        directory. Thanks to Marco Atzeri <marco.atzeri@gmail.com> for
+        bug report.
+
+Tue Aug 09 12:00:00 2011 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.46 (31:0:31) has been released
+
+        * src/glpk.h, src/Makefile
+        glpk.h was relocated from 'include' to 'src', and 'include'
+        subdir was removed; src/Makefile.am was changed appropriately.
+
+        * src/zlib/*.*
+        zlib general purpose compression library, version 1.2.5,
+        was ANSIfied and modified according to GLPK requirements and
+        included in the distribution as an external software module.
+
+        For details see src/zlib/README.
+
+        * src/glpdmx.c
+        The following new API routines were added:
+        glp_read_cnfsat  - read CNF-SAT problem data in DIMACS format
+        glp_check_cnfsat - check for CNF-SAT problem instance
+        glp_write_cnfsat - write CNF-SAT problem data in DIMACS format
+
+        * src/minisat/*.*
+        MiniSat, a CNF-SAT solver, version 1.14.1, was ANSIfied and
+        modified according to GLPK requirements and included in the
+        distribution as an external software module.
+
+        For details see minisat/README and minisat/LICENSE.
+
+        * src/glpapi19.c
+        The API routine glp_minisat1, which is a driver to the MiniSat
+        solver, was included in the package.
+
+        * doc/satcnf.*
+        The document "CNF Satisfiability Problem" was included in the
+        package. It is a supplement to the GLPK Reference Manual.
+
+        * src/glpapi20.c
+        New glpsol options (--cnf, --wcnf, and --minisat) was added.
+
+        * glpsql.c
+        Some bugs were fixed. Thanks to Xypron <xypron.glpk@gmx.de>.
+
+Sun Dec 05 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.45 (30:0:30) has been released
+
+        * glplpx01.c
+        A bug (it_cnt) in routine reset_parms was fixed.
+        Thanks to Ali Baharev <ali.baharev@gmail.com> for report.
+
+        * glpmpl03.c
+        A bug (print "text\") was fixed.
+        Thanks to Xypron <xypron.glpk@gmx.de> for report.
+
+        * glpsql.c
+        A precision bug was fixed.
+        Thanks to Xypron <xypron.glpk@gmx.de>.
+
+        * glpk.tex
+        Some typos were corrected.
+        Thanks to Robbie Morrison <robbie@actrix.co.nz>.
+
+Thu Jun 03 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.44 (29:0:29) has been released
+
+        * glpapi14.c glpmpl.h glpmpl01.c glpmpl03.c glpmpl04.c
+        Implemented suffixes for variables and constraints.
+
+        * glpmpl06.c
+        Made changes to allow comment records in CSV files.
+
+        * glpapi17.c
+        Added and documented new API routine glp_cpp to solve Critical
+        Path Problem.
+
+Sat Feb 20 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.43 (28:0:28) has been released
+
+        * glplib.h, glplib.c, glpenv.h, glpenv.c
+        The module glpenv was split into two modules glpenv and glplib.
+
+        * glpenv01.c, glpenv03.c, glpenv04.c, glpenv06.c
+        The following new API routines were added and documented:
+        glp_init_env, glp_free_env, glp_open_tee, glp_close_tee,
+        glp_error (macro), glp_difftime.
+
+        * glpapi16.c
+        New API routine glp_top_sort (topological sorting of ayclic
+        digraph) was added and documented.
+
+        * glpapi17.c
+        A serious bug was fixed in the routine glp_asn_prob_hall.
+
+        * glpnpp05.c
+        A bug was fixed in the LP/MIP preprocessor (hidden covering
+        inequalities).
+
+        * glpsql.c
+        Some improvements were made in the table driver (NULL data).
+        Thanks to Xypron <xypron.glpk@gmx.de> for contribution.
+
+        * configure.ac
+        Changes were made to use .dylib rather than .so under Mac OS.
+        Thanks to Noli Sicad <nsicad@gmail.com> for testing
+
+Wed Jan 13 12:00:00 2010 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.42 (27:0:27) has been released
+
+        * glpapi01.c, glpapi11.c, glpapi12.c, glpdmx.c
+        The following new API routines were added and documented:
+        glp_check_dup (check for duplicate elements in sparse matrix);
+        glp_sort_matrix (sort elements of the constraint matrix);
+        glp_read_prob (read problem data in GLPK format);
+        glp_write_prob (write problem data in GLPK format);
+        glp_analyze_bound (analyze active bound of non-basic variable);
+        glp_analyze_coef (analyze obj. coefficient at basic variable);
+        glp_print_ranges (print sensitivity analysis report; replaces
+        lpx_print_sens_bnds).
+
+        * glpapi20.c
+        New command-line options were added to glpsol:
+        --glp (read problem data in GLPK format);
+        --wglp (write problem data in GLPK format);
+        --lp (replaces --cpxlp);
+        --wlp (replaces --wcpxlp);
+        --ranges (print sensitivity analysis report).
+
+        * glpapi06.c
+        In the routine glp_init_smcp default value of the parameter
+        out_frq was changed to 500 (it was 200).
+
+        * glpipp.h, glpipp01.c, glpipp02.c
+        The old MIP preprocessor module was removed.
+
+        * glpapi09.c
+        Now the MIP solver uses the new MIP preprocessor (NPP).
+
+        * glplpx03.c
+        lpx_write_opb was disabled due to replacing IPP with NPP.
+
+        * glpnet09.c
+        Kellerman's heuristic to cover edges by cliques was added.
+
+        * glplib08.c
+        Recognition of special filenames "/dev/stdin", "/dev/stdout",
+        and "/dev/stderr" was added.
+
+        * glpk.tex
+        Chapter "Graph and network routines" was carried out from the
+        reference manual as a separate document.
+
+Mon Dec 21 12:00:00 2009 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.41 (26:0:26) has been released
+
+        * glpapi12.c
+        The following new API routines were added:
+        glp_transform_row (replaces lpx_transform_row);
+        glp_transform_col (replaces lpx_transform_col);
+        glp_prim_rtest (replaces lpx_prim_ratio_test);
+        glp_dual_rtest (replaces lpx_dual_ratio_test).
+        Note that values returned by glp_prim_rtest and glp_dual_rtest
+        differ from the ones retutned by the deprecated routines.
+
+        * glpnpp*.*
+        The LP/MIP preprocessor was essentially re-implemented.
+
+        * glpios03.c
+        The feature to remove inactive cuts from the active subproblem
+        was implemented.
+
+        * glpios11.c
+        The feature processing cuts stored in the cut pool was improved
+        (now it uses estimation of objective degradation).
+
+        * glpscg.*
+        Obsolete implemetation of the conflict graph was removed.
+
+        * glpmpl.h, glpmpl03.c, glpmpl04.c
+        FILE was replaced by XFILE to allow using GLPK I/O routines.
+
+        * glpsql.c, examples/sql, doc/tables.tex
+        The SQL table driver was changed to allow multiple arguments
+        separated by semicolon in SQL statements. Thanks to Xypron
+        <xypron.glpk@gmx.de>.
+
+        * glpk.h, glpapi14.c
+        New API routine glp_time was added (not documented yet).
+
+        * glpapi20.c
+        Two new options were added to glpsol: --seed value (initialize
+        pseudo-random number generator used in MathProg model with
+        specified seed value), and --ini filename (use as initial basis
+        previously saved with -w option).
+
+        * examples/xyacfs.mod
+        Thanks to Nigel Galloway <nigel_galloway@operamail.com> for
+        contribution.
+
+        * examples/dbf/*.*
+        Thanks to Noli Sicad <nsicad@gmail.com> for contribution.
+
+        * w32/*.*, w64/*.*
+        Scripts to build GLPK with Microsoft Visual Studio 2010 were
+        added. Thanks to Xypron <xypron.glpk@gmx.de> for contribution
+        and testing.
+
+Tue Nov 03 12:00:00 2009 Andrew Makhorin <mao@gnu.org>
+
+        * GLPK 4.40 (25:0:25) has been released
+
+        * glpdmx.c
+        Two new API routines were added:
+        glp_read_ccdata (read graph in DIMACS clique/coloring format);
+        glp_write_ccdata (write graph in DIMACS clique/coloring format).
+        Also an example file examples/sample.col was added.
+
+        * glpapi19.c, glpnet08.c
+        New API routine glp_wclique_exact was added. It is intended to
+        find a maximum weight clique with the exact algorithm developed
+        by Prof. P. Ostergard.
+
+        * glpnpp02.c
+        A bug was fixed in the LP preprocessor (routine npp_empty_col).
+        Thanks to Stefan Vigerske <stefan@math.hu-berlin.de> for the
+        bug report.
+
+        * glpios10.c
+        A bug was fixed and some improvements were made in the FPUMP
+        heuristic module. Thanks to Xypron <xypron.glpk@gmx.de>.
+
+        * glpapi12.c
+        A bug was fixed in the API routine glp_warm_up (dual
+        feasibility test was incorrect in maximization case). Thanks to
+        Uday Venkatadri <Uday.Venkatadri@dal.ca> for the bug report.
+
+        * glpapi16.c
+        Two new API routines were added:
+        glp_del_vertices (remove vertices from graph);
+        glp_del_arc (remove arc from graph).
+
+        * glpios09.c
+        The hybrid pseudocost branching heuristic was included in the
+        MIP solver. It is available on API level (iocp.br_tech should
+        be set to GLP_BR_PCH) and in the stand-alone solver glpsol
+        (via the command-line option --pcost). This heuristic may be
+        useful on solving hard MIP instances.
+
+        * glpios03.c
+        The branching heuristic by Driebeck and Tomlin (used in the
+        MIP solver by default) was changed to switch to branching on
+        most fractional variable if an lower bound of degradation of
+        the objective is close to zero for all branching candidates.
+
+Sun Jul 26 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.39 (24:0:24) has been released
+
+        * glpsdf.c
+        New API routines to read plain data files were added.
+
+        * glpcpx.h, glpini.h, glpscl.h
+        These headers were removed.
+
+        * glpcpx.c
+        API routines glp_read_lp and glp_write_lp to read/write files
+        in CPLEX LP format were re-implemented. Now glp_write_lp
+        correctly writes double-bounded (ranged) rows by introducing
+        slack variables rather than by duplicating the rows. The data
+        structure glp_cpxcp and routine glp_init_cpxcp were added.
+
+        * amd/*
+        The 'xfree(NULL)' bug was fixed in the AMD routines. Thanks to
+        Niels Klitgord <niels@bu.edu> for the bug report.
+
+        * glpapi16.c
+        New API routines glp_set_vertex_name, glp_create_v_index,
+        glp_find_vertex, and glp_delete_v_index were added.
+
+        * glpdmx.c
+        New API routines glp_read_asnprob, glp_write_asnprob,
+        glp_read_ccformat, and glp_write_ccformat were added (the two
+        latter routines are not documented yet).
+
+        * glpapi18.c
+        New API routines glp_check_asnprob, glp_asnprob_lp,
+        glp_asnprob_okalg, and glp_asnprob_hall were added.
+
+        * glpini01.c, glpini02.c
+        The message "Crashing..." was changed to "Constructing initial
+        basis..." due to suggestion by Thomas Kahle <tom111@gmx.de>.
+
+        * glpapi14.c
+        New API routines glp_printf, glp_vprintf, glp_malloc,
+        glp_calloc, glp_free, and glp_assert were added.
+
+        * glplpp.h, glplpp01.c, glplpp02.c
+        Old LP presolver routines were removed. Now glp_simplex uses
+        new preprocessing routines (see glpnpp).
+
+        * glpapi12.c
+        New API routine glp_warm_up was added; it replaces the routine
+        lpx_warm_up.
+
+Sat May 02 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.38 (23:0:23) has been released
+
+        * glpmps.c
+        API routines to read/write MPS files were re-implemented.
+
+        * glpspx02.c
+        Some improvements were made in the dual simplex routine.
+
+        * glpk.h
+        New structure glp_iptcp was added.
+
+        * glpnpp.h, glpnpp01.c, glpnpp02.c
+        New LP/MIP preprocessor. Currently it includes only some basic
+        routines and used only in the interior-point solver.
+
+        * glpapi08.c
+        API routine glp_interior was replaced by an improved version
+        (new LP/MIP preprocessor, new ordering algorithms).
+
+        New API routine glp_init_iptcp was added.
+
+        API routine glp_ipt_status may return two new statuses due to
+        changes in glp_interior.
+
+        * glpsol.c
+        New command-line options were added (ordering algorithm used in
+        the interior-point solver).
+
+        * amd/*.*, colamd/*.*
+        Two external software modules AMD and COLAMD/SYMAMD used in the
+        interior-point solver were included in the distribution.
+
+        For details see amd/README and colamd/README.
+
+        * glpnet03.c, glpnet04.c, glpnet05.c
+        A minor bug was fixed (_G => G_). Thanks to Nelson H. F. Beebe
+        <beebe@math.utah.edu> for bug report.
+
+Sun Mar 29 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.37 (22:0:22) has been released
+
+        * glpk.h
+        iocp.fp_heur was added to enable/disable fpump heuristic.
+
+        * glpios10.c
+        ios_feas_pump was added (feasibility pump heuristic).
+
+        * glpsol.c
+        --fpump command-line option was added.
+
+        * glpsds.c
+        Plain data set routines were added to facilitate reading plain
+        data in application programs. Currently these routines are not
+        in API, though declared in glpk.h.
+
+        * glpapi08.c
+        A bug was fixed in the internal routine restore. (Due to this
+        bug dual solution components were computed incorrectly if the
+        problem was scaled.)
+
+        * glpapi10.c, glpapi11.c
+        The following new API routines were added:
+        glp_print_sol (replaces lpx_print_sol);
+        glp_print_ipt (replaces lpx_print_ips);
+        glp_print_mip (replaces lpx_print_mip);
+        _glp_check_kkt (replaces lpx_check_kkt, lpx_check_int).
+        Now the routine lpx_print_prob (deprecated) is equivalent to
+        the routine glp_write_lp.
+
+        * glpapi18.c, glpapi19.c
+        The following new API routines were added:
+        glp_read_graph (read graph from plain text file);
+        glp_write_graph (write graph to plain text file);
+        glp_weak_comp (find all weakly connected components);
+        glp_strong_comp (find all strongly connected components).
+
+        * configure.ac, Makefile.am
+        Changes were made: (a) to allow using autoreconf/autoheader;
+        (b) to allow building glpk in a directory other than its source
+        directory. Thanks to Marco Atzeri <marco_atzeri@yahoo.it> for
+        bug report.
+
+        * examples/shiftcover.mod
+        An example model in MathProg was added.
+        Thanks to Larry D'Agostino <Larry.D'Agostino@gmacrescap.com>
+        for contribution.
+
+Fri Feb 06 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.36 (21:0:21) has been released
+
+        * glpnet06.c, glpnet07.c, glpapi19.c
+        The following new API routines were added:
+        glp_mincost_okalg     find minimum-cost flow with out-of-kilter
+                              algorithm
+        glp_maxflow_ffalg     find maximal flow with Ford-Fulkerson
+                              algorithm
+
+        * glpsol.c
+        Two new command-line options were added:
+        --mincost             read min-cost flow data in DIMACS format
+        --maxflow             read maximum flow data in DIMACS format
+
+        * doc/glpk.*
+        New edition of the reference manual was included.
+
+        * glpk.h
+        Duplicate symbols were removed to allow using swig.
+        Thanks to Kelly Westbrooks <kellywestbrooks@yahoo.com> and
+        Nigel Galloway <nigel_galloway@operamail.com> for suggestion.
+
+        * glpcpx.c
+        A minor defect was fixed in the routine glp_write_lp.
+        Thanks to Sebastien Briais <sbriais@free.fr> for bug report.
+
+        * glpsql.c
+        A minor bug was fixed. Thanks to Xypron <xypron.glpk@gmx.de>
+        for patch.
+
+        * examples/hashi.mod, examples/shikaku.mod
+        Two example models in MathProg were added. Thanks to Sebastian
+        Nowozin <nowozin@gmail.com> for contribution.
+
+        * examples/qfit.mod, examples/yacfs.mod
+        Two example models in MathProg were added. Thanks to Nigel
+        Galloway <nigel_galloway@operamail.com> for contribution.
+
+Fri Jan 09 12:00:00 2009 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.35 (20:0:20) has been released
+
+        * glpk.h, glpapi.c, glpnet.c
+        The following new API routines were added:
+        glp_create_graph      create graph
+        glp_set_graph_name    assign (change) graph name
+        glp_add_vertices      add new vertices to graph
+        glp_add_arc           add new arc to graph
+        glp_erase_graph       erase graph content
+        glp_delete_graph      delete graph
+        glp_read_mincost      read minimum cost flow problem data in
+                              DIMACS format
+        glp_write_mincost     write minimum cost flow problem data in
+                              DIMACS format
+        glp_mincost_lp        convert minimum cost flow problem to LP
+        glp_netgen            Klingman's network problem generator
+        glp_gridgen           grid-like network problem generator
+        glp_read_maxflow      read maximum flow problem data in DIMACS
+                              format
+        glp_write_maxflow     write maximum flow problem data in DIMACS
+                              format
+        glp_maxflow_lp        convert maximum flow problem to LP
+        glp_rmfgen            Goldfarb's maximum flow problem generator
+
+        * doc/glpk.*
+        New edition of the reference manual was included.
+
+        * examples/sample.min, examples/sample.max
+        Two example data files in DIMACS format were added.
+
+        * glplib04.c
+        The statement "if (c = '\n') fflush(stdout)" was added to the
+        internal routine xputc to provide "real-time" terminal output.
+        Thanks to Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for
+        suggestion.
+
+        * glpmpl05.c
+        A minor bug was fixed in the internal routine mpl_fn_time2str.
+        Thanks to Stefan Vigerske <stefan@vigerske.de> for bug report.
+
+        * w32/makefile, w64/makefile
+        The flag -O2 (/O2) was added to some makefiles.
+
+Thu Dec 04 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.34 (19:0:19) has been released
+
+        * src/glpios03.c
+        A bug was fixed in the internal routine branch_on. Thanks to
+        Nigel Galloway <nigel_galloway@operamail.com> for bug report.
+
+        * src/glpmpl05.c
+        Three new MathProg functions were included:
+        gmtime    obtaining current calendar time
+        str2time  converting character string to calendar time
+        time2str  converting calendar time to character string
+        Thanks to Xypron <xypron.glpk@gmx.de>.
+
+        * doc/glpk.*, doc/gmpl.*
+        A new edition of the GLPK reference manual and GNU MathProg
+        language description were included.
+
+Thu Oct 30 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.33 (18:0:18) has been released
+
+        * glpapi*.*
+        The following new API routines were added:
+        glp_copy_prob         copy problem object content
+        glp_exact             solve LP in exact arithmetic
+                              (makes lpx_exact deprecated)
+        glp_get_unbnd_ray     determine variable causing unboundedness
+                              (makes lpx_get_ray_info deprecated)
+        glp_interior          solve LP with interior-point method
+                              (makes lpx_interior deprecated)
+
+        * glpapi*.*
+        The following new API routines for processing models written in
+        the GNU Mathprog language were added to the package:
+        glp_mpl_alloc_wksp    allocate the translator workspace
+        glp_mpl_read_model    read and translate model section
+        glp_mpl_read_data     read and translate data section
+        glp_mpl_generate      generate the model
+        glp_mpl_build_prob    build LP/MIP instance from the model
+        glp_mpl_postsolve     postsolve the model
+        glp_mpl_free_wksp     deallocate the translator workspace
+        (These routines make lpx_read_model deprecated.)
+
+        * src/glpapi17.c, examples/glpsol.c
+        The stand-alone solver glpsol was re-implemented with new API
+        routines.
+
+        * src/glpsql.c
+        Some bugs were fixed in the SQL table driver. Thanks to Xypron
+        <xypron.glpk@gmx.de>.
+
+        * examples/cplex/*.*
+        A crude implementation of CPLEX-like interface to GLPK API was
+        added to the package. See examples/cplex/README.
+
+Fri Oct 03 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.32 (17:0:17) has been released
+
+        * glpmpl01.c
+        A bug was fixed. Due to this bug iterated expressions having
+        an indexing expression whose dummy indices are bound to some
+        values, i.e. like sum{(i+1,j,k-1) in E} x[i,j,k] are evaluated
+        incorrectly. Namely, current value of such expressions is not
+        invalidated when corresponding dummy indices (like i and k in
+        the example above) are changed, that erroneously results in the
+        same value evaluated for the first time.
+
+        * glpios03.c
+        Euclidean reduction of the local objective bound was added in
+        the routine glpios03.c.
+
+        * glpapi11.c
+        The following new branch-and-cut API routines were added:
+        glp_ios_row_attr      determine additional row attributes;
+        glp_ios_pool_size     determine current size of the cut pool;
+        glp_ios_add_row       add constraint to the cut pool;
+        glp_ios_del_row       delete constraint from the cut pool;
+        glp_ios_clear_pool    delete all constraints from the cut pool.
+
+        * glpapi08.c
+        The following new features were included in the branch-and-cut
+        solver (the API routine glp_intopt):
+        MIP presolver;
+        mixed cover cut generator;
+        clique cut generator.
+        Due to the MIP presolver glp_intopt may additionally return
+        GLP_ENOPFS and GLP_ENODFS, if primal or dual infeasibility of
+        LP relaxation is detected by the presolver. Also the return
+        code GLP_EMIPGAP was introduced to correctly indicate that the
+        mip gap tolerance is reached.
+
+        * glplpx01.c
+        Now the obsolete API routines lpx_integer and lpx_intopt are
+        completely superseded by the API routine glp_intopt that makes
+        them deprecated.
+
+        * glpmpl05.c
+        Now the table driver name "iODBC" can be specified as "ODBC".
+
+        * glpmpl03.c
+        A bug fixed in the routine free_dca.
+        Thanks to Xypron <xypron.glpk@gmx.de>.
+
+        * glpsql.c
+        A bug was fixed in the SQL table driver.
+        Thanks to Xypron <xypron.glpk@gmx.de>.
+
+        * examples/glpsol.c
+        Changes were made to allow multiple MathProg data files.
+
+        * doc/glpk.*
+        A new edition of the GLPK reference manual was included.
+
+        * doc/tables.*
+        A new edition of the supplement "Using data tables in the GNU
+        MathProg language" was included.
+
+Tue Sep 02 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.31 (16:0:16) has been released
+
+        * glpspx.h, glpspx01.c, glpspx02.c, glpapi06.c
+        The dual simplex solver (spx_dual_opt) was replaced by a new
+        implementation of the two-phase dual simplex method (spx_dual).
+        Old simplex method routines (spx_prim_opt, spx_prim_feas, and
+        spx_dual_opt) were removed from the package.
+
+        * glpk.h, glpscl.h, glpscl.c, glpapi04.c
+        New API routine glp_scale_prob was added. It replaces routine
+        lpx_scale_prob which is deprecated.
+
+        * glpk.h, glpini.h, glpini01.c, glpini02.c, glpapi05.c
+        New API routines glp_std_basis, glp_adv_basis, glp_cpx_basis
+        were added. They replace routines lpx_std_basis, lpx_adv_basis,
+        lpx_cpx_basis which are deprecated.
+
+        * glpdmp.c
+        8-byte data alignment was added to the module (sufficient for
+        both ILP32 and LP64 environments).
+
+        * glplib07.c
+        16-byte data alignment was added to the module to provide
+        compatibility with LP64 environment (8-byte is not sufficient
+        due to jmp_buf; thanks to Xypron for investigation).
+
+        * glplpx16.c
+        New version of the routine lpx_write_pb was added. Thanks to
+        Oscar Gustafsson <oscarg@isy.liu.se> for the contribution.
+
+        * w32/VC9, w64/VC9
+        Makefiles and batch files were added to build GLPK under 32-
+        and 64-bit Windows with Microsoft Visual Studio Express 2008.
+        Thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for
+        the contribution and testing.
+
+        * w32/DM, w32/OWC
+        Makefiles and batch files were added to build GLPK with Digital
+        Mars C/C++ 8.50 and Open Watcom C/C++ 1.6 (32-bit Windows).
+
+Wed Aug 13 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.30 (15:0:15) has been released
+
+        * glpspx.h, glpspx03.c, glpapi06.c
+        The primal simplex solver (spx_prim_opt, spx_prim_feas) was
+        replaced by a new implementation (spx_primal), which currently
+        provides the same features as the old version.
+
+        * glpmpl01.c, glpmpl03.c
+        Some changes were made in the MathProg translator to allow <,
+        <=, >=, and > on comparing symbolic values. Thanks to Heinrich
+        Schuchardt <heinrich.schuchardt@gmx.de> for patches.
+
+        * glplpx10.c
+        Internal routine set_d_eps in the exact LP solver was changed
+        to prevent approximation errors in case of integral data.
+        Thanks to Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
+
+XXX XXX XX 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.29 (14:0:14) has been released
+
+        * configure.ac
+        The configure script was changed to disable optional features
+        by default. For details see file INSTALL.
+
+        * glpipp02.c
+        A bug was fixed in the internal routine reduce_bounds. Thanks
+        to Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> for
+        the bug report.
+
+        * glpapi01.c
+        New API routine glp_erase_prob was added.
+
+        * glpapi13.c
+        New API routines glp_read_mps and glp_write_mps were added.
+        They replace API routines lpx_read_mps, lpx_read_freemps,
+        lpx_write_mps, and lpx_write_freemps, which are deprecated.
+
+        * glpapi14.c
+        New API routines glp_read_lp and glp_write_lp were added. They
+        replace API routines lpx_read_cpxlp and lpx_write_cpxlp, which
+        are deprecated.
+
+        * glpsql.c
+        Minor bug was fixed. Thanks to Xypron <xypron.glpk@gmx.de> for
+        the bug report.
+
+Tue Mar 25 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.28 (13:0:13) has been released
+
+        * glplib.h, glplib.c
+        Three wrapper routines xdlopen, xdlsym, and xdlclose, which
+        provide the shared library support, were added. A particular
+        version of these routines depends on the option --enable-dl
+        passed to the configure script (see file INSTALL for details).
+        Thanks to Rafael Laboissiere <rafael@debian.org> for useful
+        advices concerning the shared library support.
+
+        * glpsql.c
+        A static linking to iODBC and MySQL libraries used in the
+        MathProg table drivers was replaced by a dynamic linking to
+        corresponding shared libraries.
+        Many thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de>
+        for the contribution and to Vijay Patil <vijay.patil@gmail.com>
+        for testing this feature under Windows XP.
+
+        * glpgmp.h, glpgmp.c
+        A bug (which appeared only on 64-bit platforms) was fixed.
+        Thanks to Axel Simon <Axel.Simon@ens.fr> for the bug report.
+
+        * glpapi.c
+        A bug was fixed in the api routine glp_add_cols. (If the basis
+        is valid, adding column keeps it valid, however, col->bind was
+        set to -1 rather to 0.)
+        Thanks to Cedric[FR] <fox2113@wanadoo.fr> for the bug report.
+
+        * glplib.c
+        64-bit unsigned int type glp_ulong and corresponding routines
+        were replaced by 64-bit signed int type xlong_t.
+
+        * glpk.h, glpapi.c
+        The type glp_ulong was replaced by glp_long. This affects only
+        the api routine glp_mem_usage.
+
+        * glplib.c
+        Compressed data file support was added. This feature requires
+        the zlib data compression libraries and allows compressing and
+        decompressing .gz files "on the fly".
+
+        * glpcli.h, glpcli.c
+        Command-line interface routines were added. (This feature is
+        incomplete so far.)
+
+Sun Mar 02 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.27 (12:0:12) has been released
+
+        * glpsql.h, glpsql.c
+        Two MathProg table drivers for iODBC and MySQL contributed by
+        Heinrich Schuchardt <heinrich.schuchardt@gmx.de> were added to
+        the package.
+
+        * glpmpl05.c
+        Mathprog table driver for xBASE was added to the package.
+
+        * glpmpl03.c
+        A minor was fixed in the MathProg translator (if some field
+        specified in the table statement is missing in corresponding
+        input table, the bug causes abnormal termination). Thanks to
+        Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for the bug
+        report.
+
+        * glpmpl.h, glpmpl.c
+        STRING data type was replaced by plain character strings.
+
+Sun Feb 17 12:00:00 2008 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.26 (11:0:11) has been released
+
+        * glpmpl.h, glpmpl01.c, glpmpl03.c, glpmpl05.c
+        The table statement was implemented. Description of this new
+        feature is given in file doc/tables.txt.
+
+        * glpios03.c
+        A bug causing zero divide error on computing euclidean norm of
+        the cut coefficient vector was fixed.
+
+Wed Dec 19 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.25 (10:0:10) has been released
+
+        * glpapi10.c
+        Routines lpx_eval_tab_row and lpx_eval_tab_col were replaced by
+        glp_eval_tab_row and glp_eval_tab_col.
+
+        * glpios03.c, glpios05.c
+        Gomory's mixed integer cuts were implemented.
+
+        * glpscs.h, glpscs.c
+        Segmented character string routines are no longer used and were
+        removed from the package.
+
+Wed Nov 21 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.24 (9:0:9) has been released
+
+        * src/glplpx16.c
+        A bug was fixed in the routine lpx_write_cpxlp. If a variable
+        x has upper bound and no lower bound, it should appear in the
+        bounds section as "-inf <= x <= u", not as "x <= u". Thanks to
+        Enric Rodriguez <erodri@lsi.upc.edu> for the bug report.
+
+        * src/glpios03.c, src/glpios04.c, src/glpios05.c
+        MIR (mixed integer rounding) cuts were implemented.
+
+Sun Oct 28 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.23 (8:0:8) has been released
+
+        * src/glplib05.c, configure.ac
+        Check for vsnprintf was added.
+
+        * include/glppds.h, src/glppds.c
+        A module to scan plain data was added.
+
+        * src/glpapi09.c
+        The following new API routines were added:
+        glp_read_sol    read basic solution from text file;
+        glp_write_sol   write basic solution to text file;
+        glp_read_ipt    read interior-point solution from text file;
+        glp_write_ipt   write interior-point solution to text file;
+        glp_read_mip    read MIP solution from text file;
+        glp_write_mip   write MIP solution to text file.
+
+        * src/glpapi12.c
+        Advanced API routine glp_free_env was added.
+
+        * examples/glpsol.c
+        The following three command-line options were added:
+        --mipgap tol    set relative MIP gap tolerance
+        -r filename     read solution from filename
+        -w filename     write solution to filename
+
+Wed Sep 19 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.22 (7:0:7) has been released
+
+        * src/glpios02.c
+        A bug was fixed in the MIP preprocessor (ios_preprocess_node).
+        Thanks to Roberto Bagnara <bagnara@cs.unipr.it> (Department of
+        Mathematics, University of Parma, Italy) for the bug report.
+
+        * src/glpios02.c
+        A bug was fixed in the MIP preprocessor (col_implied_bounds),
+        due to which constraint coefficients with small magnitude could
+        lead to wrong implied bounds of structural variables.
+
+        * src/glpipp02.c
+        A similar bug was fixed in the routine reduce_bounds.
+
+        * src/glpapi01.c
+        A bug was fixed in the routines glp_set_mat_row and
+        glp_set_mat_col. (The bug appeared due to incorrect removing
+        zero elements from the row/column lists.)
+
+        * src/glplpx14.c
+        A bug was fixed in the API routines lpx_read_mps and
+        lpx_read_freemps, due to which bounds of type LI specified in
+        BOUNDS section were incorrectly processed.
+
+        * src/glplib05.c
+        A call to standard function vsprintf was replaced by a call to
+        vsnprintf for security reasons. Many thanks to Peter T. Breuer
+        <ptb@inv.it.uc3m.es> and Rafael Laboissiere <rafael@debian.org>.
+
+Tue Aug 28 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.21 (6:0:6) has been released
+
+        * glpscg.h, glpscg.c
+        Routines to maintain sparse cliqued graph were added.
+
+        * glpios02.c
+        MIP preprocessing routines were added.
+
+        * glpk.h, glpios.h, glpios03.c
+        New reasons for calling the callback routine were introduced
+        in the MIP solver.
+
+        * glpapi08.c
+        Default backtracking strategy was changed to best local bound.
+
+        * glpapi11.c
+        New API routine glp_term_out to enable/disable terminal output
+        was added.
+
+        * glprng.h, glprng02.c
+        Two routines to generate uniformly distributed pseudo-random
+        floating-point numbers were added.
+
+Thu Jul 26 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.20 (5:0:5) has been released
+
+        * glpk.h, glpapi08.c
+        The routine lpx_integer was replaced by an equivalent routine
+        glp_intopt. Also new API routine glp_init_iocp was added.
+
+        * glpiet.h, glpiet.c
+        Routines implementing the implicit enumeration tree are
+        no longer used and therefore were removed from the package.
+
+        * glpios.h, glpios01.c, glpios02, glpios03
+        Routines implementing the integer optimization suite being
+        replaced by a new version were removed from the package.
+
+        * glpmip.h, glpmip01.c, glpmip02.c
+
+        Routines implementing the B&B method being replaced by a new
+        version were removed from the package.
+
+        * glpios.h, glpios01.c, glpios02.c
+
+        Routines implementing a new version of the integer optimization
+        suite (IOS) based on the B&B method were added to the package.
+
+        * glpk.h, glpapi10.c
+        Branch-and-bound interface routines were added to the package.
+
+        * examples/tspsol.c
+        The TSP solver based on old version of the integer optimization
+        suite is no more supported and was removed from the package.
+
+        * glpipp02.c
+        An error in the routine reduce_bounds was fixed; thanks to
+        Graham Rockwell <bionomicron@gmail.com> for the bug report.
+
+        * glpk.latex
+        A new edition of the reference manual was included.
+
+Thu Jul 05 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.19 (4:0:4) has been released
+
+        The principal change is upgrading to GPLv3.
+
+        * glpapi01.c
+        A serious bug in the routine glp_del_cols was fixed; thanks to
+        Cedric[FR] <fox2113@wanadoo.fr> for the bug report. The bug
+        appeared because on deleting non-basic columns the basis header
+        remained valid, however, contained invalid (old) column ordinal
+        numbers.
+
+        * glpapi10.c
+        A new advanced API routine glp_mem_limit was added.
+
+        * glplpx01.c
+        The case GLP_EBOUND was added to the routine lpx_simplex.
+        Thanks to Cameron Kellough <Cameron.Kellough@sri.com> for the
+        bug report.
+
+        * glplpx19.c
+        An API routine lpx_write_pb to write the problem instance in
+        OPB (pseudo boolean) format format was added. Thanks to Oscar
+        Gustafsson <oscarg@isy.liu.se> for the contribution.
+
+        * glpsol.c
+        Two new options --wpb and --wnpb were added to glpsol to write
+        the problem instance in OPB format.
+
+Mon Jun 25 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.18 (3:0:3) has been released
+
+        * glplib.h
+        Type names ulong_t and uldiv_t were changed to glp_ulong and
+        glp_uldiv to avoid conflicts with standard type names on some
+        platforms. Thanks to Boris Wirtz <Boris.Wirtz@uni-oldenburg.de>
+        for the bug report.
+
+        * glpbfd.*, glpfhv.*, glplpf.*
+        LP basis factorization routines were made tidy.
+
+        * glpk.h, glpapi04.c
+        The following API routines were added:
+        glp_set_rii, glp_set_sjj, glp_get_rii, glp_get_sjj.
+
+        * glpk.h, glpapi06.c
+        The routine lpx_simplex was replaced by an equivalent routine
+        glp_simplex. Also new API routine glp_init_smcp was added.
+
+        * glpk.h, glpapi09.c
+        The following advanced API routines were added:
+        glp_bf_exists, glp_factorize, glp_bf_updated, glp_get_bfcp,
+        glp_set_bfcp, glp_get_bhead, glp_get_row_bind, glp_get_col_bind,
+        glp_ftran, glp_btran.
+
+        * glpk.latex
+        A new edition of the reference manual was included.
+
+        * examples/dea.mod, examples/food.mod, examples/food2.mod
+        Three examples in the MathProg language were added.
+        Thanks to Sebastian Nowozin <nowozin@gmail.com>.
+
+Sat May 26 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.17 (2:0:2) has been released
+
+        * glpdmp.h, glpdmp.c
+        Memory pool routines were replaced by a new version.
+
+        * glpscs.h, glpscs.c
+        Segmented string routines were replaced by a new version.
+
+        * glplpx08.c, glplpx09.c
+        Now the MIP problem may have no integer columns.
+
+        * glpapi01.c
+        The routines glp_set_mat_row, glp_set_mat_col, and glp_load_mat
+        were modified to allow zero elements (which are not stored in
+        the constraint matrix).
+
+        * glpscf.h, glpscf.c
+        Schur complement factorization routines were implemented.
+
+        * glplpf.h, glplpf.c
+        LP basis factorization routines based on LU-factorization and
+        Schur complement were implemented.
+
+        * glplpx02.c, glplpx03.c
+        New control parameter LPX_K_BFTYPE was introduced to choose the
+        basis factorization type used by the simplex method routines.
+
+        * glpsol.c
+        Three new command-line options were added to choose the basis
+        factorization type used by the simplex method routines: --luf,
+        --cbg, and --cgr.
+
+        * glpk.latex
+        A new edition of the reference manual was included.
+
+Sat May 05 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.16 (1:0:1) has been released
+
+        * glpk.h, glpapi.c, glplpx01.c, glplpx02.c
+        Names of a number basic api routines were changed and now have
+        the prefix 'glp_'. To keep backward compatibility these routines
+        are also available via their old names prefixed with 'lpx_'.
+
+        * glplpx19.c
+        Three new api routines were added: glp_version, glp_term_hook,
+        and glp_mem_usage.
+
+        * glpk.latex, gmpl.texi
+        A new edition of the reference manuals was included.
+
+        * lpglpk40.c
+        This example program is no longer supported and therefore was
+        removed from the package.
+
+Sun Feb 18 12:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.15 (0:0:0) has been released
+
+        * configure.ac, Makefile.am
+        Autotools specification files were changed to use GNU Libtool
+        that allows building the static as well as shared GLPK library.
+        Thanks to Rafael Laboissiere <rafael@debian.org>.
+
+Mon Feb 05 08:00:00 2007 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.14 has been released
+        Now GLPK conforms to ILP32, LLP64, and LP64 programming models
+        (the latter seems to be the ultimate choice regarding 64-bit
+        architectures). Note that GLPK itself is a 32-bit application,
+        and the conformity only means that the package works correctly
+        on all these arenae. Nevertheless, on 64-bit platforms it is
+        possible to use more than 4GB of memory, if necessary.
+
+        * Makefile
+        Starting from this release only the header glpk.h is needed to
+        be installed.
+
+        * glplib01.c
+        Two routines bigmul and bigdiv which performs multiplication
+        and division of unsigned integers of arbitrary precision were
+        added.
+
+        * glplib02.c
+        A set of 64-bit arithmetic routines were added.
+
+        * glplib04.c
+        Some low-level library routines were improved and renamed.
+
+        * glpcfg.h
+        The macro GLP_TM_SPEC were introduced to specify a version of
+        the time routine depending on the host environment.
+
+Mon Nov 13 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.13 has been released
+
+        * configure.in
+        '-lm' bug was fixed.
+
+        * glpbfx.h, glpbfx.c
+        Basis factorization interface routines based on exact (bignum)
+        arithmetic were implemented.
+
+        * glpssx.h, glpssx1.c, glpssx2.c
+        Simplex method routines based on exact (bignum) arithmetic were
+        implemented.
+
+        * glplpx6e.c
+        The routine lpx_exact, which is an easy-to-use driver to the
+        exact simplex method, was added.
+
+        * glpsol.c
+        Two command-line options were added: '--exact' and '--xcheck'.
+
+Wed Nov 08 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.12 has been released
+
+        * glpcfg.h
+        The package configuration file was added.
+
+        * glplib2.c
+        Alternative version of the routines umalloc, ucalloc, and ufree
+        was provided. It does not limit the amount of allocated memory
+        to INT_MAX bytes and therefore can be used on platforms where
+        sizeof(void *) > sizeof(int). To enable this version one should
+        define the preprocessor variable GLP_HUGE_MEM.
+
+        * glprng.c
+        The routine rng_create_rand was changed to initialize the
+        generator using seed = 1, not 0, to conform ISO C requirements.
+
+        * glpgmp.h, glpgmp.c
+        A set of bignum arithmetic routines implementing operations on
+        integers and rationals was added. These routines are compatible
+        with the GNU MP library.
+
+        NOTE: To attain a much better performance it is recommended to
+        use, if possible, the original GNU MP library rather than the
+        GLPK version, by defining the preprocessor variable GLP_USE_GMP.
+
+        * glplux.h, glplux.c
+        A tentative implementation of sparse LU-factorization based on
+        exact (bignum) arithmetic was added.
+
+        * glpssx.h, glpssx.c
+        A tentative implementation of some simplex method routines based
+        on exact (bignum) arithmetic was added.
+
+        * glplpx6f.c
+        A preliminary implementation of the routine lpx_exact_check was
+        added. This routine checks the current basis for primal and dual
+        feasibility using exact (bignum) arithmetic.
+
+        * examples/glpsol.c
+        The command-line option '--xcheck' was introduced to check the
+        current basis for feasibility using exact (bignum) arithmetic.
+
+Tue Jul 25 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.11 has been released.
+
+        * include/glpbfi.h, src/glpbfi.c
+        Basis factorization interface routines were added.
+
+        * include/glpluf.h, src/glpluf1.c
+        Hypersparse solution routines were added.
+
+        * include/glpinv.h, src/glpinv1.c
+        Hypersparse solution routines (fake version) were added.
+
+        * include/glpmpl.h, src/glpmpl.c
+        Built-in functions card, length, and substr were implemented.
+        Output redirection in the printf statement was implemented.
+
+        * examples/graph.mod, examples/crypto.mod
+        Two example models illustrating new features of the modeling
+        language were included.
+
+Thu May 11 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.10 has been released.
+
+        * src/glplpx8a.c
+        A fragment was added to the routines lpx_read_mps and
+        lpx_read_freemps to accept LI bound type (it is similar to LO,
+        however, additionally marks the column as integer).
+
+        * include/glpbfi.h, src/glpbfi.c
+        The module glpbfi which implements the basis factorization
+        interface (BFI) was added.
+
+        * src/glplpx7a.c
+        The routine lpx_cover_cut to generate mixed cover cuts was
+        added.
+
+        * src/glplpx7b.c
+        The routine lpx_clique_cut to generate clique cuts and related
+        routines to maintain the conflict graph were added.
+
+        * include/glplpx.h, src/glplpx5.c
+        The routine lpx_cpx_basis implementing Bixby's algorithm to
+        construct an initial LP basis was added.
+
+        * examples/glpsol.c
+        Command-line option '--bib' was added which allows building
+        an initial LP basis using Bixby's algorithm.
+        Default command-line option '--mps' was changed to '--freemps'.
+
+        * examples/cf12a.mod, examples/cf12b.mod
+        Two examples in MathProg (curve fitting problem) were added.
+        Thanks to Dr. Harley Mackenzie <hjm@hardsoftware.com>.
+
+Tue Jan 17 12:00:00 2006 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.9 has been released.
+
+        * glpipp.h, glpipp1.c, glpipp2.c
+        A MIP presolver were implemented (currently incomplete). It is
+        used internally in the routine lpx_intopt (see below).
+
+        * glplpx6d.c, glplpx7a.c
+        An advanced branch-and-bound solver (the routine lpx_intopt)
+        were implemented.
+
+        * glplpx6c.c
+        The routine lpx_check_int to check MIP feasibility conditions
+        was added.
+
+        * glplpx8a.c
+        The routine lpx_print_mip was changed to print MIP feasibility
+        conditions.
+
+        * glpmpl.h, glpmpl1.c, glpmpl3.c
+        The built-in functions sin, cos, atan, and atan2 were added to
+        the MathProg language.
+
+        * doc/lang.*
+        Some typos were fixed.
+        Thanks to Minh Ha Duong <haduong@centre-cired.fr> (CIRED, CNRS).
+
+Wed Jan 12 12:00:00 2005 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.8 has been released.
+
+        * glpspx.h, glpspx1.c, glpspx2.c, glplpx6a.c
+        Simplex method routines were changed due to a new format of the
+        constraint matrix.
+
+        * glpmat.h, glpmat.c
+        Sparse matrix routines were re-implemented using storage-by-rows
+        format.
+
+        * glpipm.h, glpipm.c, glplpx6b.c
+        Interior-point method routines were changed due to a new format
+        of sparse matrices.
+
+        * glpchol.h, glpchol.c
+        Old version of Cholesky factorization routines being replaced by
+        a new one (see glpmat.c) was removed from the package.
+
+        * glplpx8c.c
+        Minor bug was fixed in api routine lpx_read_cpxlp.
+
+Mon Aug 23 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.7 has been released.
+
+        * glplpx.h, glplpx1.c
+        New core API routines were added (but not documented yet):
+        lpx_order_matrix, lpx_create_index, lpx_find_row, lpx_find_col,
+        lpx_delete_index.
+
+        * glplpx8a.c
+        API routine lpx_read_mps was re-implemented, and two new API
+        routines lpx_read_freemps and lpx_write_freemps were added to
+        support free MPS format.
+
+        * glplpx8c.c
+        Two API routines lpx_read_cpxlp and lpx_write_cpxlp (formerly
+        named lpx_read_lpt and lpx_write_lpt) were re-implemented.
+
+        * glpmps.h, glpmps.c
+        This module formerly used in lpx_read_mps was removed from the
+        package.
+
+        * glplpt.h, glplpt.c
+        This module formerly used in lpx_read_lpt was removed from the
+        package.
+
+        * glpmip.h, glpmip1.h, glpmip2.h
+        New MIP routines mip_best_node and mip_relative_gap were added
+        due to suggestion of Brady Hunsaker <hunsaker@engr.pitt.edu>.
+
+        * glpsol.c
+        The following new command-options were added:
+        --freemps  to read problem data in free MPS format
+        --wfreemps to write problem data in free MPS format
+        --cpxlp    to read problem data in CPLEX LP format
+        --wcpxlp   to write problem data in CPLEX LP format
+        --bas      to read LP basis from a text file in MPS format
+        --wbas     to write LP basis to a text file in MPS format
+        --mostf    to use "most fractional" branching heuristic
+        --bestb    to use "best bound" backtracking heuristic
+
+        * contrib/deli/*.*
+        GLPK Delphi interface module was temporarily removed from the
+        distribution due to licensing problems.
+
+        * contrib/glpkmex/*.*
+        GLPK Matlab interface module was temporarily removed from the
+        distribution due to licensing problems.
+
+        * contrib/jni/*.*
+        GLPK Java interface module was temporarily removed from the
+        distribution due to licensing problems.
+
+Wed Aug 04 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.6 has been released.
+
+        * glpmpl.h, glpmpl1.c, glpmpl2.c, glpmpl3.c, glpmpl4.c
+        Three new statements were implemented in the GNU MathProg
+        language: solve, printf, and for. Also some bugs were fixed.
+
+        * glplpx.h, glplpx8e.c
+        Two API routines were added: lpx_read_prob and lpx_write_prob,
+        which allow reading and writing problem data in GNU LP format.
+
+        * glpsol.c
+        Three new command-line options were added: --glp (to read
+        problem data in GNU LP format), --wglp (to write problem data
+        in GNU LP format), and --name (to change problem name).
+
+        * glprng.h, glprng.c
+        A portable pseudo-random number generator was implemented as a
+        separate module.
+
+        * glplib4.c
+        The old implementation of a pseudo-random number generator was
+        removed from the package.
+
+        * doc/lang.*, doc/refman.*
+        New edition of the GLPK documentation was included.
+
+        * contrib/glpkmex/*.*
+        A new version of GLPKMEX was included in the distribution. For
+        more details see contrib/glpkmex/ChangeLog.
+
+Mon Jul 19 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.5 has been released.
+
+        * glpmip.h, glpmip1.c, glpmip2.c, glplpx6c.c
+        New implementation of the branch-and-bound method was added.
+        It replaces the old implementation, which was removed from the
+        package.
+
+        * glpies.h, glpies1.c, glpies2.c, glpies3.c
+        Modules used in the old implementation of the branch-and-bound
+        method were removed from the package.
+
+        * glplib2.c
+        Now if the preprocessor variable GLPHUGEMEM is defined, other
+        version of the routines umalloc, ucalloc, and ufree is used on
+        compiling the package. This allows avoiding memory allocation
+        problems on platforms where sizeof(void *) > sizeof(int), for
+        example, where addresses are 64-bit while integers are 32-bit.
+        The modification was made due to a bug report provided by Karel
+        Zimmermann <kzimm@diamant.jouy.inra.fr> and Christophe Caron
+        <caron@diamant.jouy.inra.fr>.
+
+Sat Jan 17 12:00:00 2004 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.4 has been released.
+
+        * glplpx.h, glplpx*.c
+        All API routines were re-implemented using new data structures.
+        Some new API routines were added and some existing API routines
+        became obsolete as shown below:
+
+        Obsolete API routine   Equivalent new API routine
+        lpx_check_name         (no more supported)
+        lpx_set_obj_c0         lpx_set_obj_coef
+        lpx_set_row_coef       (no more supported)
+        lpx_set_col_coef       lpx_set_obj_coef
+        lpx_load_mat           (no more supported)
+        lpx_load_mat3          lpx_load_matrix
+        lpx_unmark_all         (no more supported)
+        lpx_mark_row           (no more supported)
+        lpx_mark_col           (no more supported)
+        lpx_clear_mat          (no more supported)
+        lpx_del_items          lpx_del_rows, lpx_del_cols
+        lpx_get_row_bnds       lpx_get_row_type, lpx_get_row_lb,
+                               lpx_get_row_ub
+        lpx_get_col_bnds       lpx_get_col_type, lpx_get_col_lb,
+                               lpx_get_col_ub
+        lpx_get_obj_c0         lpx_get_obj_coef
+        lpx_get_row_coef       (no more supported)
+        lpx_get_col_coef       lpx_get_obj_coef
+        lpx_get_row_mark       (no more supported)
+        lpx_get_col_mark       (no more supported)
+        lpx_get_row_info       lpx_get_row_stat, lpx_get_row_prim,
+                               lpx_get_row_dual
+        lpx_get_col_info       lpx_get_col_stat, lpx_get_col_prim,
+                               lpx_get_col_dual
+        lpx_get_ips_stat       lpx_ipt_status
+        lpx_get_ips_row        lpx_ipt_row_prim, lpx_ipt_row_dual
+        lpx_get_ips_col        lpx_ipt_col_prim, lpx_ipt_col_dual
+        lpx_get_ips_obj        lpx_ipt_obj_val
+        lpx_get_mip_stat       lpx_mip_status
+        lpx_get_mip_row        lpx_mip_row_val
+        lpx_get_mip_col        lpx_mip_col_val
+        lpx_get_mip_obj        lpx_mip_obj_val
+
+        Obsolete API routines were kept for backward compatibility,
+        however, they will be removed in the future.
+
+        * doc/refman.*
+        New edition of the GLPK reference manual containing description
+        of all new API routines was included.
+
+        * contrib/glpkmex/*.*
+        GLPKMEX, a Matlab MEX interface to GLPK package, contributed by
+        Nicolo Giorgetti <giorgetti@dii.unisi.it> was included.
+
+        * doc/GLPK_FAQ.txt
+        GLPK FAQ contributed by Harley Mackenzie <hjm@bigpond.com> was
+        included.
+
+Fri Dec 12 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.3 has been released.
+
+        * configure.in
+        The bug, due to which the standard math library is not linked on
+        some platforms, was fixed.
+
+        * glpmpl3.c
+        The bug (0 ** y) was fixed in the routine fp_power.
+
+        * glpmpl.h, glpmpl1.c, glpmpl3.c
+        Some new built-in functions (round, trunc, Irand224, Uniform01,
+        Uniform, Normal01, Normal) were added to the MathProg language.
+
+        * glpmpl1.c
+        The MathProg syntax was changed to allow writing 'subj to'.
+
+        * glplpx.h, glplpx1.c, glplpx2.c
+        The new api routine lpx_get_ray_info was added.
+
+        * glplpx8a.c
+        The api routine lpx_print_sol was changed to print the number of
+        non-basic variable, which causes primal unboundness.
+
+        * glpmps.c
+        The code was changed to avoid errors on compiling the package on
+        Mac OS X. Thanks to Andre Girard <andre@inrs-emt.uquebec.ca> for
+        the bug report.
+
+        * doc/lang.*, doc/refman.*
+        Several typos were fixed and some new material was added in the
+        glpk documentation.
+
+Fri Nov 14 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.2 has been released.
+
+        * glpiet.h, glpiet.c, glpios.h, glpios1.c, glpios2.c, glpios3.c
+        A preliminary implementation of the Integer Optimization Suite
+        (IOS) was included in the package. Eventually IOS will replace
+        the Implicit Enumeration Suite (IES).
+
+        * glplpx.h, glplpx6d.c
+        A dummy version of the integer optimization routine lpx_intopt
+        was included in the package. Later this routine will replace the
+        routine lpx_integer.
+
+        * examples/glpsol.c
+        A new command-line option --int-opt was added to the solver to
+        call lpx_intopt rather than lpx_integer.
+
+        * glpbcs.h, glpbcs1.c, glpbcs2.c
+        Being replaced by IOS routines (see above) the Branch-and-Cut
+        Framework (BCS) routines were removed from the package.
+
+        * examples/tspsol.c
+        Stand-alone Symmetric TSP solver was completely re-programmed
+        using IOS routines.
+
+        * glplib.h, glplib2.c, glplib4.c
+        The random-number generator was implemented. It is based on the
+        module GB_FLIB from the Stanford GraphBase originally developed
+        by Donald Knuth.
+
+        * glphbsm.c, glplpx8a.c, glpmps.c
+        All calls to fopen/fclose were replaced by corresponding calls
+        to ufopen/ufclose due to bug reports provided by Morten Welinder
+        <terra@gnu.org> and <jpark@sfwmd.gov>.
+
+        * glpmps.c
+        The code was made re-entrant.
+
+        * glplpx8b.c
+        API routine lpx_print_sens_bnds for bounds sensitivity analysis
+        contributed by Brady Hunsaker <hunsaker@engr.pitt.edu> was added
+        to the package. This feature is also available in glpsol via the
+        command-line option --bounds.
+
+        * contrib/jni/*.*
+        New version of GLPK JNI (Java Native Interface) contributed by
+        Chris Rosebrugh <cpr@pobox.com> was added to the package.
+
+        * contrib/deli/*.*
+        GLPK DELI (Delphi Interface) contributed by Ivo van Baren
+        <i.van.baren@freeler.nl> was added to the package.
+
+        * glplpx3.c
+        Default method to scale the problem was changed to equilibration
+        scaling (lp->scale = 1 in lpx_reset_parms).
+
+        * glplpx6a.c
+        Two minor (non-critical) typos were fixed due to report provided
+        by Andrew Hamilton-Wright <andrewhw@ieee.org>.
+
+        * glplpp2.c
+        An untested case (line 941) had been tested due to bug report
+        provided by Jiri Spitz <jiri.spitz@telecom.cz>.
+
+        * w32bc5.mak, w32vc6.mak, w32vc6d.mak, d32dmc.mak
+        Several makefiles were added to allow building GLPK library for
+        some non-GNU 32-bit platforms.
+
+Sat Aug 23 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.1 has been released.
+
+        * glpmpl1.c, glpmpl3.c
+        Some bugs were fixed in the MathProg translator due to the bug
+        reports provided by Giles Thompson <gwpt1@cus.cam.ac.uk>:
+        conditional set expressions were incorrectly parsed;
+        dimen attribute was not set by default when a set was used
+        recursively in its own declaration;
+        logical expressions ... in if ... then ... else ... did not
+        work;
+        displaying set expressions did not free memory allocated for
+        temporary results.
+
+        * glpmpl3.c (reduce_terms)
+        Implementation of summation of linear forms over domain was
+        improved to reduce complexity of that operation from O(n*n) to
+        O(n*log n). The improvement was made due to a report provided
+        by Sebastien de Menten <sdementen@hotmail.com>.
+
+        * glplpx6a.c (line 1056), glpmip1.c (line 641)
+        Two minor bugs were fixed due to the bug report provided by
+        Kendall Demaree <kendal.demaree@verizon.net>.
+
+        * glplpx.h, glplpx6a.c
+        The method of one artificial variable implemented in the routine
+        lpx_prim_art and used on the phase I in the glpk simplex solver
+        has a serious defect: for some lp instances it erroneously
+        reports that the problem has no primal feasible solution. This
+        error appears when the column of the artificial variable, which
+        enters the basis to make it primal feasible, has large
+        constraint coefficients, that leads to small reduced costs of
+        non-basic variables and premature termination of the search,
+        i.e. to wrong conclusion that the problem has no primal feasible
+        solution. To avoid this defect the routine lpx_prim_feas was
+        included. It implements the method of implicit artifical
+        variables (based on minimization of the sum of infeasibilities),
+        which is a bit slower but much more robust. The routine
+        lpx_prim_feas having the same functionality now is used instead
+        the routine lpx_prim_art.
+
+        * glpinv.h, glpinv.c
+        The test used in the routine inv_update to detect low accuracy
+        after updating LU-factorization of the basis matrix was replaced
+        by a new, more robust test.
+
+        * glplpx6c.c
+        Selecting an active node to be solved next in the routine
+        btrack_bestp was changed. Now, if any integer feasible solution
+        has not been found yet, the routine chooses an active node which
+        has the minimal sum of integer infeasibilities.
+
+        * glpmip.h, glpmip1.c
+        The additional flag int_obj was included in the structure
+        MIPTREE used by the branch-and-bound. This flag is set in the
+        routine mip_create_tree and used in the routine is_better. It
+        means that the objective is integral, i.e. depends only on
+        integer variables with integer objective coefficients. The test
+        used in the routine check_integrality was also replaced by a
+        new, more reasonable one.
+
+        * glplpx1.c
+        A minor bug was fixed in the routine lpx_check_name.
+
+        * glpmpl.h, glpmpl4.c, glplpx8d.c
+        The flag skip_data was added to the parameter list of the
+        routine mpl_read_model. If this flag is set, the data section
+        in the model file is ignored. Corresponding change was made in
+        the routine lpx_read_model. Now, if both model and data files
+        are specified, the data section in the model file is ignored.
+
+        * glplpx8c.c
+        A minor bug (wrong format used for writing free columns) in the
+        routine lpx_write_lpt was fixed due to the bug report provided
+        by Bernhard Schmidt <schmidt@math.uni-augsburg.de>
+
+        * sample/glpsol.c
+        The command-line parameter --tmlim, which allows limiting the
+        solution time, was added.
+
+        * doc/lang.*, doc/refman.*
+        New edition of the GLPK documentation was included.
+
+        * java-binding/*.*
+        New version of the GLPK JNI (Java Native Interface) package was
+        included in the distribution.
+
+        * sample/lpglpk40.c
+        A non-trivial example was added. It allows using GLPK as a base
+        LP solver for Concorde, a program for solving Traveling Salesman
+        Problem (TSP). For details see comments in lpglpk40.c.
+
+        * sample/*.mod
+        Some examples of LP and MIP models written in GNU MathProg were
+        added.
+
+Tue May 06 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 4.0 has been released.
+
+        * glpmpl.h, glpmpl1.c, glpmpl2.c, glpmpl3.c, glpmpl4.c
+        The model translator for the GNU MathProg modeling language was
+        implemented and included in the package.
+
+        * glplpx.h, glplpx8d.c
+        The api routine lpx_read_model, which is an interface to the
+        MathProg translator, was included in the package.
+
+        * glplpx.h, glplpx8a.c
+        The api routine lpx_print_prob for writing LP/MIP problem data
+        in plain text format was included in the package.
+
+        * sample/glpsol.c
+        New version of the GLPK stand-alone LP/MIP solver that supports
+        the GNU MathProg modeling language was implemented.
+
+        * doc/lang.latex, doc/lang.dvi, doc/lang.ps
+        The document "GLPK: Modeling Language GNU MathProg" was included
+        in the package.
+
+        * doc/refman.latex, doc/refman.dvi, doc/refman.ps
+        New edition of the GLPK Reference Manual was included in the
+        package.
+
+        * glplpx8c.c
+        A bug in the api routine lpx_write_lpt was fixed. Due to that
+        bug an addressing error occured in the routine if the objective
+        function has the non-zero constant term.
+
+        * glplan.h, glplan1.c, glplan2.c, glplan3.c, glplan4.c,
+        * glplan5.c, glplan6.c, glplan7.c, glplan8.c, glplpx8b.c
+        All modules of the translator for the GLPK/L modeling language
+        were removed from the package, because GLPK/L being completely
+        superseded by GNU MathProg is no more supported.
+
+Tue Mar 25 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.3 has been released.
+
+        * glplpp.h, glplpp1.c, glplpp2.c
+        An implementation of the built-in LP presolver was added to the
+        package.
+
+        * glplpx.h
+        The flag presol was added to the structure LPX. This flag tells
+        the lpx_simplex whether the built-in LP presolver should be used
+        or not. By default this flag is off. Also three macros (namely
+        LPX_E_NOPFS, LPX_E_NODFS, and LPX_K_PRESOL) that concern using
+        the LP presolver were introduced.
+
+        * glplpx3.c, glplpx6a.c
+        These modules was changed to use the built-in LP presolver.
+
+        * sample/glpsol.c
+        Command line options --presol and --nopresol that concern using
+        the LP presolver were added to the stand-alone LP/MIP solver.
+
+        * glplan1.c
+        This module was changed to allow declaring sets like A[1:10] in
+        the models written in the GLPK/L modeling language.
+
+        * doc/refman.latex, doc/lang.latex
+        New editions of the documents "GLPK User's Guide" and "GLPK/L
+        Modeling Language" were included in the distribution.
+
+        * java-binding/*.*
+        The package GLPK JNI (Java Native Interface) implementing Java
+        binding for GLPK was included in the distribution. This package
+        was developed and programmed by Yuri Victorovich <yuri@gjt.org>.
+
+Tue Feb 18 12:00:00 2003 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.2.4 has been released.
+
+        * glplpx6b.c
+        The code was changed to allow auxiliary variables have non-zero
+        objective coefficients.
+
+        Also a minor bug was fixed (the constant term was not considered
+        on displaying the objective function value).
+
+        * sample/glpsol.c
+        The code was changed to fix a bug (the command-line option 'bfs'
+        was not recognized). The bug was fixed due to report provided by
+        Olivier <odwl@skynet.be>.
+
+        * glplpt.c
+        The code was changed to fix a bug (binary variables were treated
+        erroneously as integer ones).
+
+        * glplpx6b.c
+        The code was changed to fix a bug (variables that have no lower
+        bounds were incorrectly processed on converting to the standard
+        formulation). The bug was fixed due to report kindly provided by
+        Kjell Eikland <kjell.eikland@broadpark.no>.
+
+Mon Nov 11 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.2.3 has been released.
+
+        * glpmip.h, glpmip1.c
+        A preliminary implementation of the branch-and-bound driver
+        based on the implicit enumeration suite (glpies) was added to
+        the package. This module is not documented yet.
+
+        * glplpx6c.c
+        A new implementation of the api routine lpx_integer which now
+        is based on the b&b driver (see glpmip above) was included in
+        the package. This new implementation has exactly the same
+        functionality as the old version and therefore all changes are
+        transparent to the api user.
+
+        * glpbbm.h, glpbbm.c
+        * glprsm.h, glprsm1.c, glprsm2.c
+        * glplp.h, glplp.c
+        These modules were removed from the package, because they were
+        used only in the old version of the routine lpx_integer, which
+        was replaced by the new version (see glplpx6c above).
+
+        * glplpx.h, glplpx6a.c
+        The api routine lpx_check_kkt was included in the package and
+        its description was added in the reference manual. This routine
+        allows checking Karush-Kuhn-Tucker optimality conditions for an
+        LP solution.
+
+        * glplpx.h, glplpx8a.c
+        Now the api routine lpx_print_sol also prints information about
+        "solution quality" obtained via the api routine lpx_check_kkt.
+
+        * glplpx.h, glplpx8a.c
+        New api routines lpx_read_bas and lpx_write_bas were included
+        in the package and documented. The routine lpx_write_bas allows
+        writing a current basis from an LP object to a text file in the
+        MPS format. The routine lpx_read_bas allows reading a basis
+        prepared in the MPS format from a text file into an LP object.
+
+        * glplpt.c
+        The parsing routine which reads LP problem data prepared in the
+        CPLEX LP format was modified to allow specifying lower bounds
+        of variables also in the form 'variable >= lower bound' (in the
+        bounds section). This modification was made due to a notice
+        provided by Ivan Luzzi <iluzzi@libero.it>.
+
+        * glplpx.h, glplpx8c.c
+        The api routine lpx_write_lpt which allows writing LP problem
+        data from an LP object to a text file using the CPLEX LP format
+        was included in the package and documented.
+
+        * glplpx.h, glplpx3.c
+        The control parameter LPX_K_LPTORIG that affects the behavior
+        of the api routine lpx_write_lpt was introduced.
+
+        * glplan6.c
+        The semantics of the language GLPK/L was changed to allow
+        selection in case when not all mute letters of a predicate (the
+        operand that follows the keyword 'where') are presented in a
+        parameter (the operand that precedes the keyword 'where'), i.e.
+        to allow writing something like this:
+            y[j] := sum(i, x[i] where p[i,j]);
+        The paragraph "Selection" in the langauge description (page 25)
+        was also correspondingly changed. This change of the language
+        semantics was undertaken due to a notice provided by Peter Lee
+        <plee@kinggee.com.au>.
+
+        * sample/hwd.lpm
+        A nice example of LP model written in GLPK/L and contributed by
+        Peter Lee <plee@kinggee.com.au> was included in the package.
+
+        * glplpx6b.c
+        The api routine lpx_interior was modified: a) to compute dual
+        values for all structural as well as auxiliary variables; b) to
+        allow specifying non-zero objective coefficients at auxiliary
+        variables.
+
+        * sample/glpsol.c
+        Three new command-line options were added to the solver, which
+        are: --plain, --orig, and --wrlpt.
+
+Mon Oct 14 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.2.2 has been released.
+
+        * glplpt.h, glplpt.c
+        A module that reads LP/MIP problem data in CPLEX LP format was
+        implemented.
+
+        * glplpx8c.c
+        An api routine lpx_read_lpt that reads LP/MIP problem data in
+        CPLEX LP format was implemented.
+
+        * sample/glpsol.c, sample/plan.lpt
+        A new command-line option '--lpt' that allows reading LP/MIP
+        problem data in CPLEX LP format was added to the solver.
+
+        * doc/refman.latex, doc/refman.dvi, doc/refman.ps
+        A new edition of the Reference Manual was included.
+
+        * source/*.c
+        Casting to (unsigned char) was added in some calls to the
+        classification functions (isalpha, etc.). The bug was fixed due
+        to report provided by Morten Welinder <terra@diku.dk>.
+
+        * glplpx8a.c
+        The local routine mps_numb used in the routine lpx_write_mps
+        was modified to correctly format floating-point numbers that
+        have two digits in the decimal exponent. The bug was fixed due
+        to report provided by Vlahos Kiriakos <Kiriakos.Vlahos@gs.com>.
+
+        * glplan.h, glplan1.c, ..., glplan8.c
+        Several serious bugs were fixed in the language processor due
+        to reports provided by <NORBERT.PIOTROWSKI@LHSYSTEMS.COM>:
+        (a) a static search tree used to find sparse array elements was
+        sometimes overwritten that caused the message 'assertion failed'
+        to appear; the bug was fixed by creating separate search trees
+        in parsing routines; (b) a variable declared using the
+        predicate-controlled variable declaration statement had wrong
+        order of domain sets, because the variable array was built as
+        a copy of the predicate array; the bug was fixed by using the
+        internal routine transpose that coordinates mute letters (and
+        therefore domain sets) on copying sparse arrays; (c) sometimes
+        assignment statements like x[#a,#b,#c] := ... was incorrectly
+        processed; the bug was fixed by including an appropriate check
+        into the internal routine assign_stmt.
+
+        * glp_simplex.c
+        An additional check to see if all lower bounds are not greater
+        than corresponding upper bounds was included in the routine to
+        prevent wrong results to appear. Such incorrectness sometimes
+        was not detected, namely, when variables with such bounds were
+        non-basic and never entered the basis.
+
+        * glpspx1.c
+        Maximal number of simplex iterations before reinversion was
+        decreased from 100 to 50. This allowed to improve accuracy and,
+        that is more important, to reduce the solution time for many
+        serial lp problems approximately 1.5--2 times.
+
+        * glpspx2.c
+        A check to see if all elements in the column chosen to enter
+        the basis are close to zero in the routine spx_prim_chuzr was
+        temporarily removed because this check gave wrong conclusion in
+        case when the corresponding non-basic variable had zero column
+        in the constraint matrix. An analogous check to see if all
+        elements in the row chosen to leave the basis are close to zero
+        in the routine spx_dual_chuzc was also temporarily removed on
+        the same reason. The bug was fixed due to reports provided by
+        Flavio Keidi Miyazawa <fkm@ic.unicamp.br> and Vlahos Kiriakos
+        <Kiriakos.Vlahos@gs.com>.
+
+Mon Aug 12 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.2.1 has been released.
+
+        * glpbcs.h, glpbcs1.c, glpbcs2.c
+        * glpies.h, glpies1.c, glpies2.c, glpies3.c
+        A preliminary implementation of the branch-and-cut framework
+        was included in the package.
+
+        * doc/brcut.txt
+        The document "GLPK: A Preliminary Implementation of the
+        Branch-And-Cut Framework" was included in the distribution.
+
+        * sample/tspsol.c
+        An illustrative program for solving symmetric TSP based on the
+        branch-and-cut method was included in the package.
+
+        * glpdmp.h, glpdmp.c
+        A new, re-enterable version of routines for managing dynamic
+        memory pools was included in the package.
+
+        * glpavl.h, glpavl.c
+        A new, re-enterable version of routines for managing AVL search
+        trees was included in the package.
+
+        * glplib.h, glplib2.c
+        Two new low-level routines ufopen and ufclose were included in
+        the package.
+
+        * glplpx.h, glplpx7.c
+        The following new api routines were added: lpx_eval_activity,
+        lpx_eval_red_cost, lpx_reduce_form, lpx_mixed_gomory.
+
+        * glptsp.h, glptsp.c
+        A module for reading TSP data using TSPLIB format was included
+        in the package.
+
+Mon Jul 15 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.2 has been released.
+
+        * glplpx.h, glplpx1.c, glplpx2.c
+        The identifier 'class' (used as a member name in the structure
+        LPX and as an argument name in the routine lpx_set_class) was
+        changed to 'clss' in order to avoid conflicts with C++ reserved
+        words.
+
+        * glpk.h, glplpx.h, glplpx1.c, glplpx2.c, glplpx6a.c,
+        * glplpx6b.c, glplpx6c.c, glplpx7.c, glplpx8.c
+        The following new api routines were added: lpx_set_obj_name,
+        lpx_get_obj_name, lpx_get_row_mark, lpx_get_col_mark,
+        lpx_transform_row, lpx_transform_col, lpx_prim_ratio_test,
+        lpx_dual_ratio_test, lpx_interior, lpx_get_ips_stat,
+        lpx_get_ips_row, lpx_get_ips_col, lpx_get_ips_obj, lpx_read_lpm,
+        lpx_write_mps, lpx_print_ips.
+
+        * glpsol.c
+        The solver was completely re-programmed using new api routines.
+
+        * lang.latex, lang.dvi, lang.ps
+        New edition of the document "GLPK: Modeling Language GLPK/L"
+        was included in the distribution.
+
+        * refman.latex, refman.dvi, refman.ps
+        New edition of the document "GLPK: Reference Manual" (which
+        contains descriptions of all new api routines) was included in
+        the distribution.
+
+        * glpapi.h, glpapi1.c, glpapi2.c, glpapi3.c, glpapi4.c
+        These files (which contain old api routines) were removed from
+        the package.
+
+        * glpipm1.c, glpipm2.c
+        The file glpipm1.c was renamed to glpipm.c. The file glpipm2.c
+        was used only by old api routines and therefore was removed from
+        the package.
+
+        * language.texinfo
+        Old version of the document "GLPK: Modeling Language GLPK/L" was
+        removed from the distribution.
+
+Mon May 27 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.1 has been released.
+
+        * glplpx.h, glplpx1.c, glplpx2.c, glplpx3.c, glplpx4.c,
+        * glplpx5.c, glplpx6.c, glplpx7.c, glplpx8.c
+        A preliminary implementation of new API routines was completed.
+
+        * refman.latex, refman.dvi, refman.ps
+        A draft edition of the document "GLPK Reference Manual", which
+        describes new API routines, was included.
+
+        * glplib3.c
+        A bug in measuring long time intervals was fixed up.
+
+        * glprsm3.c
+        This module contains some obsolete routines not longer used and
+        therefore it was removed from the package (into the subdirectory
+        'oldsrc').
+
+        * glprsm.h
+        Some declarations related to the module 'glprsm3.c' (see above)
+        were removed.
+
+        * guide.texinfo
+        The document "GLPK User's Guide" describing old API routines was
+        removed from the package (into the subdirectory 'oldsrc').
+
+        * newapi.txt
+        The document "New GLPK API Routines" was removed at all, because
+        it is superseded by the new reference manual (see above).
+
+Mon May 13 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.8 has been released.
+
+        * glplpx.h, glplpx1.c, glplpx2.c, glplpx3.c, glplpx4.c,
+        * glplpx5.c, glplpx6.c, glplpx7.c
+        A preliminary (currently incomplete) implementation of new api
+        routines was included.
+
+        * sample/newsamp.c
+        A sample program for the new api routines was included.
+
+        * newapi.txt
+        A draft of the document "New GLPK API Routines" was included.
+
+        * glpapi2.c, glpapi5.c, glpapi6.c
+        These modules (which contain the api routines glp_call_rsm1,
+        glp_simplex1, glp_pivot_in, glp_pivot_out) were removed from the
+        package (to the subdirectory 'oldsrc') since these routines are
+        functionally superseded by the new api routines.
+
+        * glpk.h, glpapi2.c, glpapi3.c, glpapi4.c
+        The api routines glp_simplex2, glp_call_ipm1, glp_call_bbm1 were
+        renamed to glp_simplex, glp_interior, glp_integer, respectively.
+
+        * sample/glpsol.c
+        Some command-line options (which got obsolete due to the recent
+        changes in api) were excluded.
+
+        * doc/guide.texinfo
+        New edition of the document "GLPK User's Guide" was included in
+        the distribution to reflect the changes in some api routines.
+
+        * doc/libref.texinfo
+        This document was removed from the package (to the subdirectory
+        'oldsrc') since it describes the library routines, most of which
+        got obsolete and no longer used.
+
+        * Makefile.in
+        A minor bug was fixed up due to bug report from Hans Schwengeler
+        <Hans.Schwengeler@unibas.ch>.
+
+Mon Apr 22 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.7 has been released.
+
+        * glpduff.h, glpduff.c, glpspx.h, glpspx1.c, glpspx2.c,
+        * glpapi7.c
+        These modules were replaced by a new implementation of the
+        simplex method and therefore they were removed from the package
+        (however they still can be found in the subdirectory 'oldsrc').
+
+        * glprsm1.c
+        The routine crash_aa was replaced by a new implementation and
+        therefore it was removed from the file 'glprsm1.c'.
+
+        * glplpx.h, glplpx.c, glpspx.h, glpspx1.c, glpspx2.c, glpspx3.c,
+        * glpspx4.c, glpapi7.c
+        New (currently incomplete) implementation of the simplex method
+        components was included in the package.
+
+Thu Mar 28 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.6 has been released.
+
+        * glpluf.h, glpluf.c, glpinv.h, glpinv.c
+        New version of LU-factorization and basis maintenance routines
+        (based on Forrest-Tomlin updating technique) was implemented.
+
+        * glpeta.h, glpeta.c, glpfhv.h, glpfhv.c, glpgel.h, glpgel.c,
+        * glppfi.h, glppfi.c, glprfi.h, glprfi.c
+        These routines implement some other forms of the basis matrix.
+        Now they became obsolete being functionally superseded by the
+        new version of basis maintenance routines (see above) and were
+        removed from the package (however they still can be found in the
+        subdirectory 'oldsrc').
+
+        * glpbbm.c, glprsm.h, glprsm1.h, glprsm2.h, glpspx.h, glpspx2.c,
+        * glprsm2.c, glpsol.c
+        Necessary changes were made in order to use the new version of
+        basis maintenance routines.
+
+Tue Jan 29 12:00:00 2002 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.5 has been released.
+        Structure of the package was re-organized in order to simplify
+        its maintenance.
+
+        * doc/guide.texinfo
+        New edition of the document "GLPK User's Guide" was included in
+        the distribution. Now the document includes descriptions of some
+        additional API routines recently added to the package.
+
+        * doc/newapi.txt
+        The document "Additional GLPK API Routines" was removed from the
+        distribution, because the corresponding material was included in
+        the user's guide (see above).
+
+Mon Dec 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.4 has been released.
+
+        * glpspx.h, glpspx1.c, glpspx2.c, glpapi/glp_simplex2.h
+        A new, more efficient version of the two-phase primal simplex
+        method was implemented (advanced initial basis, projected
+        steepest edge, recursive computations of solution components).
+
+        * glpapi/glp_call_bbm1.c
+        Now LP relaxation can be solved either using rsm1_driver(), or
+        using glp_simplex2(). The choice is controlled by the parameter
+        'meth' (a member of struct bbm1).
+
+        * sample/glpsol.c
+        The new implementation of the simplex method is now used by
+        default. The old version is available via --old-sim option.
+
+        * glpmat/gm_scaling.c
+        Now this routine displays only two lines: an initial "quality"
+        and a final "quality".
+
+        * glplp/prepro_lp.c
+        Identifiers 'fmin' and 'fmax' renamed to 'f_min' and 'f_max' in
+        order to avoid conflict with <math.h>. The bug was fixed due to
+        report provided by Sami Farin <sfarin@ratol.fi>.
+
+Wed Oct 03 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.3 has been released.
+
+        * glprsm/harris_row.c, glprsm/harris_col.c
+        The relative tolerance used on the first pass of the two-pass
+        ratio test was replaced by the absolute tolerance.
+
+        * glprsm/rsm_primal.c, glprsm/rsm_feas.c, glprsm/rsm_dual.c
+        The absolute tolerance passed to the two-pass ratio test routine
+        was decaresed (for both primal and dual simplex).
+
+        These changes were made in order to improve numerical stability
+        of the simplex method.
+
+        * glprsm/glp_call_rsm1.c, glprsm/glp_call_bbm1.c,
+        * glprsm/glp_simplex1, glprsm/glp_pivoting.c
+        Default form of the inverse was changed from RFI to AFI.
+
+Mon Sep 24 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.2 has been released.
+
+        * glpfhv.h, glpfhv.c
+        New version of the basis maintaining routines was implemented.
+        These routines, which are based on so called FHV-factorization
+        (a variety of LU-factorization) and Gustavson's data structures,
+        perform the main operations on the basis matrix faster at the
+        expense of some worsening numerical accuracy.
+
+        * glprsm.h, glprsm/afi.c
+        The routines, which implement AFI (Advanced Form of the
+        Inverse) based on FHV-factorization, were added to the package.
+        This new form is available via the parameter form = 3 (on API
+        level) or via the option --afi (in GLPSOL solver).
+
+        * EFI was renamed to PFI
+        In order to correct terminology the acronym EFI (Elimination
+        Form of the Inverse) was replaced by PFI (Product Form of the
+        Inverse) everywhere in the source code and the documentation.
+
+        * glpset/umalloc.c, glpset/ucalloc.c
+        * glpset/get_atom.c, glpset/get_atomv.c
+        These memory management routines were changed in order *not* to
+        clear allocated memory blocks by binary zeros.
+
+Wed Aug 01 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0.1 has been released.
+
+        * glpapi/old_api.c, glplp/extract_lp.c, store_lpsol.c
+        Old API routines were deleted from the package.
+
+        * include/glpk.h, include/glpapi.h, include/glplp.h
+        Specifications of old API routines and data structures were
+        removed from the headers.
+
+        * sample/glpsol.c
+        New version of the stand-alone solver GLPSOL that now uses new
+        API routines was implemented.
+
+        * glpapi/glp_set_row_fctr.c, glpapi/glp_set_col_fctr.c,
+        * glpapi/glp_get_row_fctr.c, glpapi/glp_get_col_fctr.c,
+        * glpapi/glp_scale_prob.c
+        Scaling routines were added.
+
+        * glpapi/glp_write_mps.c
+        The routine for writing problem data in MPS format was added.
+
+        * glpapi/glp_simplex1.c
+        Comprehensive driver to the simplex method was added.
+
+        * glpapi/glp_pivoting.c
+        The routines glp_pivot_in() and glp_pivot_out() intended for
+        basis maintaining were added.
+
+        * glprsm/create_rsm.c, glprsm/delete_rsm.c, glprsm/scale_rsm.c,
+        * glprsm/build_basis.c
+        Additional low level routines related to the simplex method
+        were added.
+
+        * glpk.h, glpapi.h, glprsm.h
+        Additional specifications for new routines and data structures
+        were added.
+
+        * sample/lpglpk30.c
+        A non-trivial example was added. It allows using GLPK as a base
+        LP solver for Concorde, a program for solving Traveling Salesman
+        Problem (TSP). For details see comments in 'lpglpk30.c'.
+
+        * doc/newapi.txt
+        The document "Additional GLPK API Routines" that describes some
+        new API routines was included.
+
+Thu Jul 19 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 3.0 has been released.
+
+        Now GLPK is provided with new API, which is intended for using
+        the package in more complex algorithmic schemes.
+
+        * glpapi/old_api.c
+        All routines related to old API were gathered in one file named
+        'old_api.c'.
+
+        * glpapi/*.c
+        These routines that implement new API were added to the package.
+
+        * include/glpk.h, include/glpapi.h
+        Specifications of new API routines and data structures were
+        added to these headers. Specifications of old API routines and
+        data structures were locked by #ifdef GLP_OLD_API directive.
+
+        * doc/guide.texinfo
+        New edition of the document "GLPK User's Guide" that correspond
+        to new API was included.
+
+Thu Jun 14 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 2.4.1 has been released.
+
+        * doc/glpk_ml.texinfo
+        The new document "Modeling Language GLPK/L" was included.
+
+        * doc/glpk_ug.texinfo
+        New edition of the document "GLPK User's Guide" was included.
+
+        * doc/language.txt
+        The preliminary document "GLPK/L Modeling Language: A Brief
+        description" was removed from the distribution, because it has
+        been replaced by the new document "Modeling Language GLPK/L".
+
+        * glplang/l_spar.c
+        The routine comparison() was re-programmed in order to
+        implement the relation operation as specified in the language
+        description.
+
+        * glpmip.h, glpmip/*.c
+        The partition 'glpmip' was renamed to 'glpbbm'.
+
+Thu May 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 2.4 has been released.
+
+        Now GLPK includes an implementation of a preliminary version of
+        the GLPK/L modeling language.
+
+        * glplang.h, glplang/*.c
+        The header 'glplang.h' and a set of routines that implements
+        the GLPK/L language processor (the partition 'glplang') were
+        added to the package.
+
+        * doc/language.txt
+        The document "GLPK/L Modeling Language: A Brief Description
+        (Supplement to GLPK User's Guide)" in plain text format was
+        included in the package (see the file 'language.txt' in the
+        subdirectory 'doc' of the distribution).
+
+        * ex/model1.lpm, ex/model2.lpm
+        Two examples of model descriptions written in GLPK/L were added
+        to the package.
+
+        * sample/glpsol.c
+        This program was modified in order: a) to allow processing
+        model description written in GLPK/L; b) to allow solving pure
+        LP problem using the interior point method.
+
+        * sample/glpipm.c
+        This program was removed from the package, because its function
+        was passed to the GLPSOL solver.
+
+        * Makefile.in
+        This file was changed in order to install the GLPSOL solver
+        executable.
+
+Mon Apr 09 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 2.3 has been released.
+
+        * glpmip.h, glpmip/*.c
+        These routines (that implement the branch-and-bound method) were
+        re-programmed in order to improve robustness of implementation.
+        In particular, heuristic routines were carried out from the main
+        driver routine.
+
+        Additional GLPK API routines were documented.
+
+        New edition of the document "GLPK User's Guide" was included in
+        the package.
+
+        The preliminary document "Mixed Integer Programming Using GLPK
+        Version 2.2 (Supplement to GLPK User's Guide)" was removed from
+        the package, because this material was included in GLPK User's
+        Guide.
+
+Thu Mar 15 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 2.2 has been released.
+
+        Now GLPK includes a tentative implementation of the
+        branch-and-bound procedure based on the dual simplex method for
+        mixed integer linear programming (MIP).
+
+        The preliminary document "Mixed Integer Programming Using GLPK
+        Version 2.2 (Supplement to GLPK User's Guide)" was included into
+        the package in plain text format (see the file 'mip.txt' in the
+        subdirectory 'doc' of the distribution).
+
+        * glpmip.h, glpmip/*.c, glpapi/glp_integer.c
+        These routines (that implement the branch-and-bound method) were
+        added to the package.
+
+        * sample/glpsol.c
+        This program was modified in order to allow solving LP and MIP
+        problems.
+
+        * glprsm/rsm_primal.c, glprsm/rsm_dual.c, glprsm/rsm_feas.c,
+        * glprsm/rsm1_driver.c
+        These routines (which are drivers to basic components of the
+        revised simplex method) were added to the package.
+
+Mon Feb 19 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 2.1 has been released.
+
+        * glprsm.h, glprsm/*.c
+        These routines (that implement components of the revised simplex
+        method) were re-programmed and documented.
+
+        The document "GLPK Implementation of the Revised Simplex Method"
+        was included into the package.
+
+Thu Jan 25 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 2.0 has been released.
+
+        Now GLPK includes a tentative implementation of the primal-dual
+        interior point method for large-scale linear programming (for
+        more details see the file `NEWS' in the distribution). A number
+        of routines related to the interior point method were added to
+        the package.
+
+        * insist.c
+        The routine `insist' and the macro of the same name were
+        introduced into the package in order to replace the standard
+        macro `assert'. Some routines require the expression specified
+        in the `assert' macro to be evaluated, but compiling the package
+        with NDEBUG option prevents from that. This bug was fixed due to
+        bug report provided by Peter A. Huegler <phuegler@bsco.com>.
+
+        * Makefile.in
+        Minor bug was fixed due to a patch provided by Alexandre Oliva
+        <oliva@lsd.ic.unicamp.br>.
+
+Wed Jan 10 12:00:00 2001 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 1.1.2 has been released.
+
+        * umalloc.c, ufree.c, create_pool.c, get_atom.c, get_atomv.c
+        These routines were changed in order to fix a bug due to
+        report provided by Andrew Hood <ajhood@fl.net.au>. Because of
+        this bug data alignment error occured on the Sparc computer.
+
+Tue Dec 14 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 1.1.1 has been released.
+
+        Minor bug was fixed in `Makefile.in'.
+
+        GLPK Library Reference was included.
+
+Mon Nov 27 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 1.1 has been released.
+
+        Minor changes were made in order to co-ordinate GLPK routines
+        and their descriptions.
+
+        GLPK User's Guide was included.
+
+Fri Oct 20 12:00:00 2000 Andrew Makhorin <mao@mai2.rcnet.ru>
+
+        * GLPK 1.0 has been released.
Index: deps/glpk/INSTALL
===================================================================
--- deps/glpk/INSTALL	(revision 9)
+++ deps/glpk/INSTALL	(revision 9)
@@ -0,0 +1,209 @@
+INSTALLING GLPK ON YOUR COMPUTER
+********************************
+
+Unpacking the distribution file
+-------------------------------
+The GLPK package (like all other GNU software) is distributed in the
+form of a packed archive. It is one file named `glpk-X.Y.tar.gz', where
+`X' is the major version number and `Y' is the minor version number;
+for example, the archive name might be `glpk-4.15.tar.gz'.
+
+In order to prepare the distribution for installation you should:
+
+1. Copy the GLPK distribution file to a working directory.
+
+2. Unpack the distribution file with the following command:
+
+      gzip -d glpk-X.Y.tar.gz
+
+   After unpacking the distribution file is automatically renamed to
+   `glpk-X.Y.tar'.
+
+3. Unarchive the distribution file with the following command:
+
+      tar -x < glpk-X.Y.tar
+
+   It automatically creates the subdirectory `glpk-X.Y' containing the
+   GLPK distribution.
+
+Configuring the package
+-----------------------
+After unpacking and unarchiving the GLPK distribution you should
+configure the package, i.e. automatically tune it for your platform.
+
+Normally, you should just `cd' to the directory `glpk-X.Y' and run the
+`configure' script, e.g.
+
+      ./configure
+
+The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It also creates file `config.h' containing platform-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+Running `configure' takes about a few seconds. While it is running, it
+displays some messages that tell you what it is doing. If you don't want
+to see the messages, run `configure' with its standard output redirected
+to `dev/null'; for example, `./configure > /dev/null'.
+
+By default both static and shared versions of the GLPK library will be
+compiled. Compilation of the shared librariy can be turned off by
+specifying the `--disable-shared' option to `configure', e.g.
+
+      ./configure --disable-shared
+
+If you encounter problems building the library try using the above
+option, because some platforms do not support shared libraries.
+
+The GLPK package has some optional features listed below. By default
+all these features are disabled. To enable a feature the corresponding
+option should be passed to the configure script.
+
+--with-gmp           Enable using the GNU MP bignum library
+
+   This feature allows the exact simplex solver to use the GNU MP
+   bignum library. If it is disabled, the exact simplex solver uses the
+   GLPK bignum module, which provides the same functionality as GNU MP,
+   however, it is much less efficient.
+
+   For details about the GNU MP bignum library see its web page at
+   <http://gmplib.org/>.
+
+--with-zlib          Enable using the zlib data compression library
+
+   This feature allows GLPK API routines and the stand-alone solver to
+   read and write compressed data files performing compression and
+   decompression "on the fly" (compressed data files are recognized by
+   suffix `.gz' in the file name). It may be useful in case of large
+   MPS files to save the disk space.
+
+   For details about the zlib compression library see its web page at
+   <http://www.zlib.net/>.
+
+--enable-dl          The same as --enable-dl=ltdl
+--enable-dl=ltdl     Enable shared library support (GNU)
+--enable-dl=dlfcn    Enable shared library support (POSIX)
+
+   Currently this feature is only needed to provide dynamic linking to
+   ODBC and MySQL shared libraries (see below).
+
+   For details about the GNU shared library support see the manual at
+   <http://www.gnu.org/software/libtool/manual/>.
+
+--enable-odbc        Enable using ODBC table driver (libiodbc)
+--enable-odbc=unix   Enable using ODBC table driver (libodbc)
+
+   This feature allows transmitting data between MathProg model objects
+   and relational databases accessed through ODBC.
+
+   For more details about this feature see the supplement "Using Data
+   Tables in the GNU MathProg Modeling Language" (doc/tables.*).
+
+--enable-mysql       Enable using MySQL table driver (libmysql)
+
+   This feature allows transmitting data between MathProg model objects
+   and MySQL relational databases.
+
+   For more details about this feature see the supplement "Using Data
+   Tables in the GNU MathProg Modeling Language" (doc/tables.*).
+
+Compiling the package
+---------------------
+Normally, you can compile (build) the package by typing the command:
+
+      make
+
+It reads `Makefile' generated by `configure' and performs all necessary
+jobs.
+
+If you want, you can override the `make' variables CFLAGS and LDFLAGS
+like this:
+
+      make CFLAGS=-O2 LDFLAGS=-s
+
+To compile the package in a different directory from the one containing
+the source code, you must use a version of `make' that supports `VPATH'
+variable, such as GNU `make'. `cd' to the directory where you want the
+object files and executables to go and run the `configure' script.
+`configure' automatically checks for the source code in the directory
+that `configure' is in and in `..'. If for some reason `configure' is
+not in the source code directory that you are configuring, then it will
+report that it can't find the source code. In that case, run `configure'
+with the option `--srcdir=DIR', where DIR is the directory that contains
+the source code.
+
+Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+
+      CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+
+      env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Here are the `make' variables that you might want to override with
+environment variables when running `configure'.
+
+For these variables, any value given in the environment overrides the
+value that `configure' would choose:
+
+CC:      C compiler program. The default is `cc'.
+
+INSTALL: Program used to install files. The default value is `install'
+         if you have it, otherwise `cp'.
+
+For these variables, any value given in the environment is added to the
+value that `configure' chooses:
+
+DEFS:    Configuration options, in the form `-Dfoo -Dbar ...'.
+
+LIBS:    Libraries to link with, in the form `-lfoo -lbar ...'.
+
+Checking the package
+--------------------
+To check the package, i.e. to run some tests included in the package,
+you can use the following command:
+
+      make check
+
+Installing the package
+----------------------
+Normally, to install the GLPK package you should type the following
+command:
+
+      make install
+
+By default, `make install' will install the package's files in
+`usr/local/bin', `usr/local/lib', etc. You can specify an installation
+prefix other than `/usr/local' by giving `configure' the option
+`--prefix=PATH'. Alternately, you can do so by consistently giving a
+value for the `prefix' variable when you run `make', e.g.
+
+      make prefix=/usr/gnu
+      make prefix=/usr/gnu install
+
+After installing you can remove the program binaries and object files
+from the source directory by typing `make clean'. To remove all files
+that `configure' created (`Makefile', `config.status', etc.), just type
+`make distclean'.
+
+The file `configure.ac' is used to create `configure' by a program
+called `autoconf'. You only need it if you want to remake `configure'
+using a newer version of `autoconf'.
+
+Uninstalling the package
+------------------------
+To uninstall the GLPK package, i.e. to remove all the package's files
+from the system places, you can use the following command:
+
+      make uninstall
+
+========================================================================
Index: deps/glpk/Makefile.am
===================================================================
--- deps/glpk/Makefile.am	(revision 9)
+++ deps/glpk/Makefile.am	(revision 9)
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in ##
+
+ACLOCAL_AMFLAGS=-I m4
+
+SUBDIRS = src examples
+
+## eof ##
Index: deps/glpk/Makefile.in
===================================================================
--- deps/glpk/Makefile.in	(revision 9)
+++ deps/glpk/Makefile.in	(revision 9)
@@ -0,0 +1,719 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
+	THANKS config.guess config.sub depcomp install-sh ltmain.sh \
+	missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-dvi-recursive install-exec-recursive \
+	install-html-recursive install-info-recursive \
+	install-pdf-recursive install-ps-recursive install-recursive \
+	installcheck-recursive installdirs-recursive pdf-recursive \
+	ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+	$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+	distdir dist dist-all distcheck
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  { test ! -d "$(distdir)" \
+    || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+         && rm -fr "$(distdir)"; }; }
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+to_host_path_cmd = @to_host_path_cmd@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = src examples
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+	@:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+	else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@fail= failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+	@fail= failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(MKDIR_P) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+	$(am__remove_distdir)
+
+dist-lzma: distdir
+	tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+	$(am__remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
+	$(am__remove_distdir)
+
+dist-tarZ: distdir
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__remove_distdir)
+
+dist-shar: distdir
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__remove_distdir)
+
+dist dist-all: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lzma*) \
+	  lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir); chmod a+w $(distdir)
+	mkdir $(distdir)/_build
+	mkdir $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build \
+	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@$(am__cd) '$(distuninstallcheck_dir)' \
+	&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \
+	ctags-recursive install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+	all all-am am--refresh check check-am clean clean-generic \
+	clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
+	dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
+	distcheck distclean distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+	ps ps-am tags tags-recursive uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: deps/glpk/Makefile_MMIX
===================================================================
--- deps/glpk/Makefile_MMIX	(revision 9)
+++ deps/glpk/Makefile_MMIX	(revision 9)
@@ -0,0 +1,169 @@
+# Build GLPK for MMIX with GCC cross-compiler
+
+#**********************************************************************#
+# You can use this Makefile to build GLPK with GCC cross-compiler for  #
+# MMIX. No configuring is needed.                                      #
+#                                                                      #
+# MMIX is a 64-bit RISC computer for the third millennium designed by  #
+# Prof. Donald Knuth. For details see:                                 #
+#                                                                      #
+# http://www-cs-faculty.stanford.edu/~knuth/mmix.html                  #
+# http://en.wikipedia.org/wiki/MMIX                                    #
+# http://www.malgil.com/mmix                                           #
+#                                                                      #
+# The GNU MMIX compiler tool-suite (GCC backend, binutils, and newlib) #
+# was developed by Hans-Peter Nilsson. You may follow his instructions #
+# to build and install the MMIX tools; see:                            #
+#                                                                      #
+# http://bitrange.com/mmix/install.html                                #
+#**********************************************************************#
+
+GCC = mmix-gcc
+AR = mmix-ar
+MMIX = mmix
+CFLAGS = -O2
+
+OBJSET = \
+src/glpapi01.o \
+src/glpapi02.o \
+src/glpapi03.o \
+src/glpapi04.o \
+src/glpapi05.o \
+src/glpapi06.o \
+src/glpapi07.o \
+src/glpapi08.o \
+src/glpapi09.o \
+src/glpapi10.o \
+src/glpapi11.o \
+src/glpapi12.o \
+src/glpapi13.o \
+src/glpapi14.o \
+src/glpapi15.o \
+src/glpapi16.o \
+src/glpapi17.o \
+src/glpapi18.o \
+src/glpapi19.o \
+src/glpapi20.o \
+src/glpapi21.o \
+src/glpavl.o \
+src/glpbfd.o \
+src/glpbfx.o \
+src/glpcpx.o \
+src/glpdmp.o \
+src/glpdmx.o \
+src/glpenv01.o \
+src/glpenv02.o \
+src/glpenv03.o \
+src/glpenv04.o \
+src/glpenv05.o \
+src/glpenv06.o \
+src/glpenv07.o \
+src/glpenv08.o \
+src/glpfhv.o \
+src/glpgmp.o \
+src/glphbm.o \
+src/glpini01.o \
+src/glpini02.o \
+src/glpios01.o \
+src/glpios02.o \
+src/glpios03.o \
+src/glpios04.o \
+src/glpios05.o \
+src/glpios06.o \
+src/glpios07.o \
+src/glpios08.o \
+src/glpios09.o \
+src/glpios10.o \
+src/glpios11.o \
+src/glpios12.o \
+src/glpipm.o \
+src/glplib01.o \
+src/glplib02.o \
+src/glplib03.o \
+src/glplpf.o \
+src/glplpx01.o \
+src/glplpx02.o \
+src/glplpx03.o \
+src/glpluf.o \
+src/glplux.o \
+src/glpmat.o \
+src/glpmpl01.o \
+src/glpmpl02.o \
+src/glpmpl03.o \
+src/glpmpl04.o \
+src/glpmpl05.o \
+src/glpmpl06.o \
+src/glpmps.o \
+src/glpnet01.o \
+src/glpnet02.o \
+src/glpnet03.o \
+src/glpnet04.o \
+src/glpnet05.o \
+src/glpnet06.o \
+src/glpnet07.o \
+src/glpnet08.o \
+src/glpnet09.o \
+src/glpnpp01.o \
+src/glpnpp02.o \
+src/glpnpp03.o \
+src/glpnpp04.o \
+src/glpnpp05.o \
+src/glpnpp06.o \
+src/glpqmd.o \
+src/glprgr.o \
+src/glprng01.o \
+src/glprng02.o \
+src/glpscf.o \
+src/glpscl.o \
+src/glpsdf.o \
+src/glpspm.o \
+src/glpspx01.o \
+src/glpspx02.o \
+src/glpsql.o \
+src/glpssx01.o \
+src/glpssx02.o \
+src/glptsp.o \
+src/amd/amd_1.o \
+src/amd/amd_2.o \
+src/amd/amd_aat.o \
+src/amd/amd_control.o \
+src/amd/amd_defaults.o \
+src/amd/amd_dump.o \
+src/amd/amd_info.o \
+src/amd/amd_order.o \
+src/amd/amd_post_tree.o \
+src/amd/amd_postorder.o \
+src/amd/amd_preprocess.o \
+src/amd/amd_valid.o \
+src/colamd/colamd.o \
+src/minisat/minisat.o \
+src/zlib/adler32.o \
+src/zlib/compress.o \
+src/zlib/crc32.o \
+src/zlib/deflate.o \
+src/zlib/gzclose.o \
+src/zlib/gzlib.o \
+src/zlib/gzread.o \
+src/zlib/gzwrite.o \
+src/zlib/infback.o \
+src/zlib/inffast.o \
+src/zlib/inflate.o \
+src/zlib/inftrees.o \
+src/zlib/trees.o \
+src/zlib/uncompr.o \
+src/zlib/zio.o \
+src/zlib/zutil.o
+
+.c.o:
+	$(GCC) $(CFLAGS) -Isrc -o $@ -c $<
+
+all: libglpk.a glpsol.mmo
+
+libglpk.a: $(OBJSET)
+	$(AR) cru libglpk.a $(OBJSET)
+
+glpsol.mmo: examples/glpsol.o libglpk.a
+	$(GCC) $(CFLAGS) -o glpsol.mmo examples/glpsol.o libglpk.a -lm
+
+check: glpsol.mmo
+	$(MMIX) glpsol.mmo --mps examples/plan.mps
Index: deps/glpk/NEWS
===================================================================
--- deps/glpk/NEWS	(revision 9)
+++ deps/glpk/NEWS	(revision 9)
@@ -0,0 +1,1607 @@
+GLPK 4.47 (release date: Sep 09, 2011)
+
+        The new API routine glp_intfeas1 was added to the package.
+        This routine is a tentative implementation of the integer (0-1)
+        feasibility solver based on the CNF-SAT solver (which currently
+        is MiniSat). It may be used in the same way as glp_intopt to
+        find either any integer feasible solution or a solution, for
+        which the objective function is not worse than the specified
+        value. Detailed description of this routine can be found in the
+        document "CNF Satisfiability Problem", which is included in the
+        distribution (see doc/cnfsat.pdf).
+
+        The following two options were added to glpsol:
+
+        --minisat       translate 0-1 feasibility problem to CNF-SAT
+                        problem and solve it with glp_intfeas1/MiniSat
+                        (if the problem instance is already in CNF-SAT
+                        format, no translation is performed)
+
+        --objbnd bound  add inequality obj <= bound (minimization) or
+                        obj >= bound (maximization) to 0-1 feasibility
+                        problem (this option assumes --minisat)
+
+        The paint-by-numbers puzzle model (pbn.mod) included in the
+        distribution is a nice example of the 0-1 feasibility problem,
+        which can be efficiently solved with glp_intfeas1/MiniSat. This
+        model along with a brief instruction (pbn.pdf) and benchmark
+        examples from <webpbn.com> encoded in GNU MathProg (*.dat) can
+        be found in subdirectory examples/pbn/.
+
+        The glpsol lp/mip solver was modified to bypass postprocessing
+        of MathProg models if the solution reported is neither optimal
+        nor feasible.
+
+        A minor bug in examples/Makefile.am was fixed to correctly
+        build glpk in a separate directory. Thanks to Marco Atzeri
+        <marco.atzeri@gmail.com> for bug report and patch.
+
+GLPK 4.46 (release date: Aug 09, 2011)
+
+        The following new API routines were added:
+
+        glp_read_cnfsat    read CNF-SAT problem data in DIMACS format
+        glp_check_cnfsat   check for CNF-SAT problem instance
+        glp_write_cnfsat   write CNF-SAT problem data in DIMACS format
+        glp_minisat1       solve CNF-SAT problem instance with MiniSat
+
+        The routine glp_minisat1 is a driver to MiniSat, a CNF-SAT
+        solver developed by Niklas Een and Niklas Sorensson, Chalmers
+        University of Technology, Sweden. This routine is similar to
+        the routine glp_intopt, however, it is intended to solve a 0-1
+        programming problem instance, which is the MIP translation of
+        a CNF-SAT problem instance.
+
+        Detailed description of these new API routines can be found in
+        the document "CNF Satisfiability Problem", which is included in
+        the distribution (see files doc/cnfsat.tex and doc/cnfsat.pdf).
+
+        The following new glpsol command-line options were added:
+
+        --cnf filename     read CNF-SAT problem instance in DIMACS
+                           format from filename and translate it to MIP
+        --wcnf filename    write CNF-SAT problem instance in DIMACS
+                           format to filename
+        --minisat          solve CNF-SAT problem instance with MiniSat
+                           solver
+
+        The zlib compression library (version 1.2.5) was ANSIfied,
+        modified according to GLPK requirements and included in the
+        distribution as an external software module. Thus, now this
+        feature is platform independent.
+
+        Some bugs were fixed in the SQL table driver. Thanks to Xypron
+        <xypron.glpk@gmx.de>.
+
+GLPK 4.45 (release date: Dec 05, 2010)
+
+        This is a bug-fix release.
+
+        Several bugs/typos were fixed. Thanks to
+        Xypron <xypron.glpk@gmx.de>,
+        Robbie Morrison <robbie@actrix.co.nz>, and
+        Ali Baharev <ali.baharev@gmail.com> for reports.
+
+        Some glpk documents was re-formatted and merged into a single
+        document. Now the glpk documentation consists of the following
+        three main documents (all included in the distribution):
+
+        GLPK: Reference Manual
+
+        GLPK: Graph and Network Routines
+
+        Modeling Language GNU MathProg: Language Reference
+
+GLPK 4.44 (release date: Jun 03, 2010)
+
+        The following suffixes for variables and constraints were
+        implemented in the MathProg language:
+
+        .lb     (lower bound),
+        .ub     (upper bound),
+        .status (status in the solution),
+        .val    (primal value), and
+        .dual   (dual value).
+
+        Thanks to Xypron <xypron.glpk@gmx.de> for draft implementation
+        and testing.
+
+        Now the MathProg language allows comment records (marked by
+        '#' in the very first position) in CSV data files read with the
+        table statements. Note that the comment records may appear only
+        in the beginning of a CSV data file.
+
+        The API routine glp_cpp to solve the Critical Path Problem was
+        added and documented.
+
+GLPK 4.43 (release date: Feb 20, 2010)
+
+        This is a maintainer release.
+
+        `configure.ac' was changed to allow building the package under
+        Mac OS and Darwin with ODBC support.
+        Thanks to Xypron <xypron.glpk@gmx.de> for suggestions and Noli
+        Sicad <nsicad@gmail.com> for testing.
+
+        The SQL table driver was improved to process NULL data. Thanks
+        to Xypron <xypron.glpk@gmx.de>.
+
+        Some bugs were fixed in the LP/MIP preprocessor.
+
+GLPK 4.42 (release date: Jan 13, 2010)
+
+        The following new API routines were added:
+
+        glp_check_dup         check for duplicate elements in sparse
+                              matrix
+        glp_sort_matrix       sort elements of the constraint matrix
+        glp_read_prob         read problem data in GLPK format
+        glp_write_prob        write problem data in GLPK format
+        glp_analyze_bound     analyze active bound of non-basic variable
+        glp_analyze_coef      analyze objective coefficient at basic
+                              variable
+        glp_print_ranges      print sensitivity analysis report (this
+                              routine replaces lpx_print_sens_bnds and
+                              makes it deprecated)
+
+        For description of these new routines and the GLPK LP/MIP
+        format see a new edition of the reference manual included in
+        the distribution. (Chapter "Graph and network API routines" was
+        carried out from the main reference manual and included in the
+        distribution as a separate document.)
+
+        The following new command-line options were added to the stand-
+        alone solver glpsol:
+        --glp filename        read problem data in GLPK format
+        --wglp filename       write problem data in GLPK format
+        --ranges filename     print sensitivity analysis report (this
+                              option replaces --bounds)
+
+        Now all GLPK routines performing file I/O support special
+        filenames "/dev/stdin", "/dev/stdout", and "/dev/stderr", which
+        can be specified in the same way as regular filenames. This
+        feature is plaform-independent.
+
+GLPK 4.41 (release date: Dec 21, 2009)
+
+        The following new API routies were added:
+
+        glp_transform_row     transform explicitly specified row
+        glp_transform_col     transform explicitly specified column
+        glp_prim_rtest        perform primal ratio test
+        glp_dual_rtest        perform dual ratio test
+
+        For description of these new routines see a new edition of the
+        reference manual included in the distribution.
+
+        The following API routines are deprecated: lpx_transform_row,
+        lpx_transform_col, lpx_prim_ratio_test, lpx_dual_ratio_test.
+
+        Some improvements were made in the MIP solver (glp_intopt).
+
+        The SQL table driver used to read/write data in MathProg models
+        was changed to allow multiple arguments separated by semicolon
+        in SQL statements. Thanks to Xypron <xypron.glpk@gmx.de>.
+
+        Two new options were added to the glpsol stand-alone solver:
+        --seed value (to initialize the pseudo-random number generator
+        used in MathProg models with specified value), and
+        --ini filename (to use a basis previously saved with -w option
+        as an initial basis on solving similar LP's).
+
+        Two new MathProg example models were included. Thanks to
+        Nigel Galloway <nigel_galloway@operamail.com> and Noli Sicad
+        <nsicad@gmail.com> for contribution.
+
+        Scripts to build GLPK with Microsoft Visual Studio 2010 for
+        both 32-bit and 64-bit Windows were included. Thanks to Xypron
+        <xypron.glpk@gmx.de> for contribution and testing.
+
+GLPK 4.40 (release date: Nov 03, 2009)
+
+        The following new API routines were added:
+
+        glp_del_vertices      remove vertices from graph
+        glp_del_arc           remove arc from graph
+        glp_wclique_exact     find maximum weight clique with the exact
+                              algorithm developed by Prof. P. Ostergard
+        glp_read_ccdata       read graph in DIMACS clique/coloring
+                              format
+        glp_write_ccdata      write graph in DIMACS clique/coloring
+                              format
+
+        For description of these new routines see a new edition of the
+        reference manual included in the distribution.
+
+        The hybrid pseudocost branching heuristic was included in the
+        MIP solver. It is available on API level (iocp.br_tech should
+        be set to GLP_BR_PCH) and in the stand-alone solver glpsol
+        (via the command-line option --pcost). This heuristic may be
+        useful on solving hard MIP instances.
+
+        The branching heuristic by Driebeck and Tomlin (used in the
+        MIP solver by default) was changed to switch to branching on
+        most fractional variable if an lower bound of degradation of
+        the objective is close to zero for all branching candidates.
+
+        A bug was fixed in the LP preprocessor (routine npp_empty_col).
+        Thanks to Stefan Vigerske <stefan@math.hu-berlin.de> for the
+        bug report.
+
+        A bug was fixed and some improvements were made in the FPUMP
+        heuristic module. Thanks to Xypron <xypron.glpk@gmx.de>.
+
+        A bug was fixed in the API routine glp_warm_up (dual
+        feasibility test was incorrect in maximization case). Thanks to
+        Uday Venkatadri <Uday.Venkatadri@dal.ca> for the bug report.
+
+GLPK 4.39 (release date: Jul 26, 2009)
+
+        The following new API routines were added:
+
+        glp_warm_up           "warm up" LP basis
+        glp_set_vertex_name   assign (change) vertex name
+        glp_create_v_index    create vertex name index
+        glp_find_vertex       find vertex by its name
+        glp_delete_v_index    delete vertex name index
+        glp_read_asnprob      read assignment problem data in DIMACS
+                              format
+        glp_write_asnprob     write assignment problem data in DIMACS
+                              format
+        glp_check_asnprob     check correctness of assignment problem
+                              data
+        glp_asnprob_lp        convert assignment problem to LP
+        glp_asnprob_okalg     solve assignment problem with the
+                              out-of-kilter algorithm
+        glp_asnprob_hall      find bipartite matching of maxumum
+                              cardinality with Hall's algorithm
+
+        Also were added some API routines to read plain data files.
+
+        The API routines glp_read_lp and glp_write_lp to read/write
+        files in CPLEX LP format were re-implemented. Now glp_write_lp
+        correctly writes double-bounded (ranged) rows by introducing
+        slack variables rather than by duplicating the rows.
+
+        For description of these new routines see a new edition of the
+        reference manual included in the distribution.
+
+        The 'xfree(NULL)' bug was fixed in the AMD routines. Thanks to
+        Niels Klitgord <niels@bu.edu> for bug report.
+
+        The message "Crashing..." was changed to "Constructing initial
+        basis..." due to suggestion by Thomas Kahle <tom111@gmx.de>.
+
+        Some typos were corrected in glpsol output messages. Thanks to
+        Xypron <xypron.glpk@gmx.de> for patch.
+
+GLPK 4.38 (release date: May 02, 2009)
+
+        API routines glp_read_mps and glp_write_mps were improved.
+
+        Some improvements were made in the dual simplex routines.
+
+        Two external software modules AMD and COLAMD were included in
+        the distribution (for more details please see src/amd/README
+        and src/colamd/README). Now they are used in the interior-point
+        solver to reorder the matrix prior to Cholesky factorization.
+
+        API routine glp_ipt_status may return two new statuses due to
+        changes in the routine glp_interior. For details please see the
+        reference manual included in the distribution.
+
+        A minor bug was fixed in the graph/network routines. Thanks to
+        Nelson H. F. Beebe <beebe@math.utah.edu> for bug report.
+
+GLPK 4.37 (release date: Mar 29, 2009)
+
+        The 0-1 Feasibility Pump heuristic was included in the GLPK
+        integer optimizer glp_intopt. On API level the heuristic can be
+        enabled by setting the parameter fp_heur in glp_iocp to GLP_ON.
+        This feature is also available in the solver glpsol through
+        command-line option '--fpump'. For more details please see the
+        reference manual included in the distribution.
+
+        The following new API routines were added:
+
+        glp_print_sol         write basic solution in printable format
+        glp_print_ipt         write interior-point solution in printable
+                              format
+        glp_print_mip         write MIP solution in printable format
+        glp_read_graph        read (di)graph from plain text file
+        glp_write_graph       write (di)graph to plain text file
+        glp_weak_comp         find all weakly connected components
+        glp_strong_comp       find all strongly connected components
+
+        The following API routines are deprecated: lpx_print_sol,
+        lpx_print_ips, lpx_print_mip, lpx_print_prob (the latter is
+        equivalent to glp_write_lp).
+
+        A bug was fixed in the interior-point solver (glp_interior) to
+        correctly compute dual solution components when the problem is
+        scaled.
+
+        The files configure.ac and Makefile.am were changed:
+        (a) to allow using autoreconf/autoheader;
+        (b) to allow building the package in a directory other than its
+            source directory.
+        Thanks to Marco Atzeri <marco_atzeri@yahoo.it> for bug report.
+
+        An example model in the GNU MathProg language was added.
+        Thanks to Larry D'Agostino <Larry.D'Agostino@gmacrescap.com> for
+        contribution.
+
+GLPK 4.36 (release date: Feb 06, 2009)
+
+        The following new API routines were added to the package:
+
+        glp_mincost_okalg     find minimum-cost flow with out-of-kilter
+                              algorithm
+        glp_maxflow_ffalg     find maximal flow with Ford-Fulkerson
+                              algorithm
+
+        For detailed description of these new routines and related data
+        structures see chapter "Graph and Network API Routines" in a new
+        edition of the reference manual included in the distribution.
+
+        The following two new command-line options were added to the
+        solver glpsol:
+
+        --mincost             read min-cost flow data in DIMACS format
+        --maxflow             read maximum flow data in DIMACS format
+
+        Duplicate symbols in the header glpk.h were removed to allow
+        using swig.
+        Thanks to Kelly Westbrooks <kellywestbrooks@yahoo.com> and
+        Nigel Galloway <nigel_galloway@operamail.com> for suggestion.
+
+        A minor defect was fixed in the routine glp_write_lp.
+        Thanks to Sebastien Briais <sbriais@free.fr> for bug report.
+
+        A minor bug was fixed in the SQL module.
+        Thanks to Xypron <xypron.glpk@gmx.de> for patch.
+
+        Some new example models in the GNU MathProg modeling language
+        were added. Thanks to Sebastian Nowozin <nowozin@gmail.com> and
+        Nigel Galloway <nigel_galloway@operamail.com> for contribution.
+
+GLPK 4.35 (release date: Jan 09, 2009)
+
+        The following new API routines were added to the package:
+
+        glp_create_graph      create graph
+        glp_set_graph_name    assign (change) graph name
+        glp_add_vertices      add new vertices to graph
+        glp_add_arc           add new arc to graph
+        glp_erase_graph       erase graph content
+        glp_delete_graph      delete graph
+        glp_read_mincost      read minimum cost flow problem data in
+                              DIMACS format
+        glp_write_mincost     write minimum cost flow problem data in
+                              DIMACS format
+        glp_mincost_lp        convert minimum cost flow problem to LP
+        glp_netgen            Klingman's network problem generator
+        glp_gridgen           grid-like network problem generator
+        glp_read_maxflow      read maximum flow problem data in DIMACS
+                              format
+        glp_write_maxflow     write maximum flow problem data in DIMACS
+                              format
+        glp_maxflow_lp        convert maximum flow problem to LP
+        glp_rmfgen            Goldfarb's maximum flow problem generator
+
+        For detailed description of these new routines and related data
+        structures see chapter "Graph and Network API Routines" in a new
+        edition of the reference manual included in the distribution.
+
+        A minor change were made in the internal routine xputc. Thanks
+        to Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for suggestion.
+
+        A minor bug was fixed in the internal routine mpl_fn_time2str.
+        Thanks to Stefan Vigerske <stefan@vigerske.de> for bug report.
+
+GLPK 4.34 (release date: Dec 04, 2008)
+
+        The GNU MathProg modeling language was supplemented with three
+        new built-in functions:
+
+        gmtime    obtaining current calendar time
+        str2time  converting character string to calendar time
+        time2str  converting calendar time to character string
+
+        (Thanks to Xypron <xypron.glpk@gmx.de>.)
+
+        For detailed description of these functions see Appendix A in
+        the document "Modeling Language GNU MathProg", a new edition of
+        which was included in the distribution.
+
+        A bug was fixed in the MIP solver. Thanks to Nigel Galloway
+        <nigel_galloway@operamail.com> for bug report.
+
+        A new makefile was added to build the GLPK DLL with Microsoft
+        Visual Studio Express 2008 for 64-bit Windows. Thanks to Xypron
+        <xypron.glpk@gmx.de> for contribution and testing.
+
+GLPK 4.33 (release date: Oct 30, 2008)
+
+        The following new API routines were added to the package:
+        glp_copy_prob         copy problem object content
+        glp_exact             solve LP in exact arithmetic
+                              (makes lpx_exact deprecated)
+        glp_get_unbnd_ray     determine variable causing unboundedness
+                              (makes lpx_get_ray_info deprecated)
+        glp_interior          solve LP with interior-point method
+                              (makes lpx_interior deprecated)
+
+        The following new API routines for processing models written in
+        the GNU Mathprog language were added to the package:
+        glp_mpl_alloc_wksp    allocate the translator workspace
+        glp_mpl_read_model    read and translate model section
+        glp_mpl_read_data     read and translate data section
+        glp_mpl_generate      generate the model
+        glp_mpl_build_prob    build LP/MIP instance from the model
+        glp_mpl_postsolve     postsolve the model
+        glp_mpl_free_wksp     deallocate the translator workspace
+        (These routines make lpx_read_model deprecated.)
+
+        For description of all these new API routines see the reference
+        manual included in the distribution.
+
+        A crude implementation of CPLEX-like interface to GLPK API was
+        added to the package. Currently it allows using GLPK as a core
+        LP solver for Concorde, a well known computer code for solving
+        the symmetric TSP. For details see examples/cplex/README.
+
+        Some bugs were fixed in the SQL table driver. Thanks to Xypron
+        <xypron.glpk@gmx.de>.
+
+GLPK 4.32 (release date: Oct 03, 2008)
+
+        The following new features were included in the MIP solver
+        (the API routine glp_intopt):
+
+        *  MIP presolver
+        *  mixed cover cut generator
+        *  clique cut generator
+        *  Euclidean reduction of the objective value
+
+        Due to changes the routine glp_intopt may additionally return
+        GLP_ENOPFS, GLP_ENODFS, and GLP_EMIPGAP.
+
+        The API routines lpx_integer are lpx_intopt are deprecated,
+        since they are completely superseded by glp_intopt.
+
+        The following new branch-and-cut API routines were added:
+        glp_ios_row_attr      determine additional row attributes
+        glp_ios_pool_size     determine current size of the cut pool
+        glp_ios_add_row       add constraint to the cut pool
+        glp_ios_del_row       delete constraint from the cut pool
+        glp_ios_clear_pool    delete all constraints from the cut pool
+
+        For description of these new routines see the reference manual
+        included in the distribution.
+
+        The stand-alone solver glpsol was changed to allow multiple
+        data files.
+
+        A new edition of the supplement "Using Data Tables in the GNU
+        MathProg Modeling Language" was included.
+
+        As usual, some bugs were fixed (in the MathProg translator).
+        Thanks to Xypron <xypron.glpk@gmx.de>.
+
+GLPK 4.31 (release date: Sep 02, 2008)
+
+        The core LP solver based on the dual simplex method was
+        re-implemented and now it provides both phases I and II.
+
+        The following new API routines were added:
+        glp_scale_prob  automatic scaling of problem data
+        glp_std_basis   construct standard initial LP basis
+        glp_adv_basis   construct advanced initial LP basis
+        glp_cpx_basis   construct Bixby's initial LP basis
+
+        For description of these new routines see the reference manual
+        included in the distribution.
+
+        The following API routines are deprecated:
+        lpx_scale_prob, lpx_std_basis, lpx_adv_basis, lpx_cpx_basis.
+
+        Necessary changes were made in memory allocation routines to
+        resolve portability issues for 64-bit platforms.
+
+        New version of the routine lpx_write_pb to write problem data
+        in OPB (pseudo boolean format) was added to the package. Thanks
+        to Oscar Gustafsson <oscarg@isy.liu.se> for the contribution.
+
+        Two new makefiles were added to build the package for 32- and
+        64-bit Windows with Microsoft Visual Studio Express 2008.
+        Thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de> (aka
+        Xypron) for the contribution and testing.
+
+        Two new makefiles were added to build the package with Digital
+        Mars C/C++ 8.50 and Open Watcom C/C++ 1.6 (for 32-bit Windows).
+
+GLPK 4.30 (release date: Aug 13, 2008)
+
+        The core LP solver based on the primal simplex method was
+        re-implemented to allow its further improvements. Currently the
+        new version provides the same features as the old one, however,
+        it is a bit faster and more numerically stable.
+
+        Some changes were made in the MathProg translator to allow <,
+        <=, >=, and > on comparing symbolic values. Thanks to Heinrich
+        Schuchardt <heinrich.schuchardt@gmx.de> for patches.
+
+        Internal routine set_d_eps in the exact LP solver was changed
+        to prevent approximation errors in case of integral data.
+        Thanks to Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
+
+GLPK 4.29 (release date: Jul 06, 2008)
+
+        The configure script was changed to disable all optional
+        features by default. For details please see file INSTALL.
+
+        The following new API routines were added:
+        glp_erase_prob  erase problem object content
+        glp_read_mps    read problem data in MPS format
+        glp_write_mps   write problem data in MPS format
+        glp_read_lp     read problem data in CPLEX LP format
+        glp_write_lp    write problem data in CPLEX LP format
+
+        For description of these new routines see the reference manual
+        included in the distribution.
+
+        The following API routines are deprecated:
+        lpx_read_mps, lpx_read_freemps, lpx_write_mps,
+        lpx_write_freemps, lpx_read_cpxlp, and lpx_write_cpxlp.
+
+        Two bugs were fixed. Thanks to
+        Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> and
+        Xypron <xypron.glpk@gmx.de> for bug report.
+
+GLPK 4.28 (release date: Mar 25, 2008)
+
+        The iODBC and MySQL table drivers, which allows transmitting
+        data between MathProg model objects and relational databases,
+        were re-implemented to replace a static linking by a dynamic
+        linking to corresponding shared libraries.
+        Many thanks to Heinrich Schuchardt <heinrich.schuchardt@gmx.de>
+        for the contribution, Rafael Laboissiere <rafael@debian.org>
+        for useful advices concerning the shared library support under
+        GNU/Linux, and Vijay Patil <vijay.patil@gmail.com> for testing
+        this feature under Windows XP.
+
+        A new optional feature was added to the package. This feature
+        is based on the zlib data compression library and allows GLPK
+        API routines and the stand-alone solver to read and write
+        compressed data files performing compression/decompression "on
+        the fly" (compressed data files are recognized by suffix `.gz'
+        in the file name). It may be useful in case of large MPS files
+        to save the disk space (up to ten times).
+
+        The `configure' script was re-implemented. Now it supports the
+        following specific options:
+
+        --with-gmp           Enable using the GNU MP bignum library
+        --without-gmp        Disable using the GNU MP bignum library
+        --with-zlib          Enable using the zlib data compression
+                             library
+        --without-zlib       Disable using the zlib data compression
+                             library
+        --enable-dl          Enable shared library support (auto check)
+        --enable-dl=ltdl     Enable shared library support (GNU)
+        --enable-dl=dlfcn    Enable shared library support (POSIX)
+        --disable-dl         Disable shared library support
+        --enable-odbc        Enable using ODBC table driver
+        --disable-odbc       Disable using ODBC table driver
+        --enable-mysql       Enable using MySQL table driver
+        --disable-mysql      Disable using MySQL table driver
+
+        For more details please see file INSTALL.
+
+GLPK 4.27 (release date: Mar 02, 2008)
+
+        Three new table drivers were added to the MathProg translator:
+
+        xBASE built-in table driver, which allows reading and writing
+        data in .dbf format (only C and N fields are supported);
+
+        MySQL table driver, which provides connection to a MySQL
+        database;
+
+        iODBC table driver, which provides connection to a database
+        through ODBC.
+
+        The MySQL and iODBC table drivers were contributed to GLPK by
+        Heinrich Schuchardt <heinrich.schuchardt@gmx.de>.
+
+        The table driver is a program module which allows transmitting
+        data between MathProg model objects and external data tables.
+
+        For detailed description of the table statement and table
+        drivers see the document "Using Data Tables in the GNU MathProg
+        Modeling Language" (file doc/tables.txt) included in the
+        distribution. Some examples which demonstrate using MySQL and
+        iODBC table drivers can be found in subdirectory examples/sql.
+
+GLPK 4.26 (release date: Feb 17, 2008)
+
+        The table statement was implemented in the GNU MathProg
+        modeling language. This new feature allows reading data from
+        external tables into model objects such as sets and parameters
+        as well as writing results of computations to external tables.
+
+        A table is a (unordered) set of records, where each record
+        consists of the same number of fields, and each field is
+        provided with a unique symbolic name called the field name.
+
+        Currently the GLPK package has the only built-in table driver,
+        which supports tables in the CSV (comma-separated values) file
+        format. This format is very simple and supported by almost all
+        spreadsheets and database management systems.
+
+        Detailed description of the table statement and CSV format can
+        be found in file doc/tables.txt, included in the distribution.
+
+GLPK 4.25 (release date: Dec 19, 2007)
+
+        A tentative implementation of Gomory's mixed integer cuts was
+        included in the branch-and-cut solver. To enable generating
+        Gomory's cuts the control parameter gmi_cuts passed to the
+        routine glp_intopt should be set to GLP_ON. This feature is
+        also available in the solver glpsol through command-line option
+        '--gomory'. For more details please see the reference manual
+        included in the distribution.
+
+GLPK 4.24 (release date: Nov 21, 2007)
+
+        A tentative implementation of MIR (mixed integer rounding) cuts
+        was included in the MIP solver. To enable generating MIR cuts
+        the control parameter mir_cuts passed to the routine glp_intopt
+        should be set to GLP_ON. This feature is also available in the
+        stand-alone solver glpsol via command-line option '--mir'. For
+        more details please see the reference manual included in the
+        distribution.
+
+        The implementation is mainly based on the following two papers:
+
+        1. H. Marchand and L. A. Wolsey. Aggregation and mixed integer
+           rounding to solve MIPs. CORE discussion paper 9839, CORE,
+           Universite catholique de Louvain, June 1998.
+
+        2. G. Andreello, A. Caprara, and M. Fischetti. Embedding cuts
+           in a Branch&Cut framework. Preliminary draft, October 2003.
+
+        MIR cuts can be generated on any level of the search tree that
+        makes the GLPK MIP solver to be a real branch-and-cut solver.
+
+        A bug was fixed in the routine lpx_write_cpxlp. If a variable
+        x has upper bound and no lower bound, it should appear in the
+        bounds section as "-inf <= x <= u", not as "x <= u". Thanks to
+        Enric Rodriguez <erodri@lsi.upc.edu> for the bug report.
+
+GLPK 4.23 (release date: Oct 28, 2007)
+
+        The following new API routines were added:
+
+        glp_read_sol    read basic solution from text file
+        glp_write_sol   write basic solution to text file
+        glp_read_ipt    read interior-point solution from text file
+        glp_write_ipt   write interior-point solution to text file
+        glp_read_mip    read MIP solution from text file
+        glp_write_mip   write MIP solution to text file
+
+        For description of these routines and corresponding file
+        formats see Chapter "API Routines", Section "Utility routines"
+        in the reference manual included in the distribution.
+
+        Advanced API routine glp_free_env was added. It may be used by
+        the application program to free all resources allocated by GLPK
+        routines.
+
+        The following three new command-line options were added to the
+        solver glpsol:
+
+        --mipgap tol    set relative MIP gap tolerance
+        -r filename     read solution from filename
+        -w filename     write solution to filename
+
+GLPK 4.22 (release date: Sep 19, 2007)
+
+        This is a maintainer release.
+
+        A bug was fixed in the MIP preprocessor (ios_preprocess_node).
+        Thanks to Roberto Bagnara <bagnara@cs.unipr.it> (Department of
+        Mathematics, University of Parma, Italy) for the bug report.
+
+        A bug was fixed in the MIP preprocessor (col_implied_bounds),
+        due to which constraint coefficients with small magnitude could
+        lead to wrong implied bounds of structural variables.
+
+        A similar bug was fixed in the routine reduce_bounds.
+
+        A bug was fixed in the routines glp_set_mat_row and
+        glp_set_mat_col. (The bug appeared due to incorrect removing
+        zero elements from the row/column lists.)
+
+        A bug was fixed in the API routines lpx_read_mps and
+        lpx_read_freemps, due to which bounds of type LI specified in
+        BOUNDS section were incorrectly processed.
+
+        A call to standard function vsprintf was replaced by a call to
+        vsnprintf for security reasons. Many thanks to Peter T. Breuer
+        <ptb@inv.it.uc3m.es> and Rafael Laboissiere <rafael@debian.org>.
+
+GLPK 4.21 (release date: Aug 28, 2007)
+
+        Additional reasons for calling the callback routine used in the
+        MIP solver (glp_intopt) were introduced. Currently the following
+        reasons are supported:
+
+        * request for subproblem selection
+        * request for preprocessing
+        * request for row generation
+        * request for heuristic solution
+        * request for cut generation
+        * request for branching
+        * better integer solution found
+
+        A basic preprocessing component used to improve subproblem
+        formulations by tightening bounds of variables was included in
+        the MIP solver. Depending on the control parameter pp_tech
+        passed to the routine glp_intopt the preprocessing can be
+        performed either on the root level or on all levels (default)
+        or can be disabled.
+
+        Backtracking heuristic used by default in the MIP solver was
+        changed to the "best local bound".
+
+        For more details see Chapter "Advanced API routines", Section
+        "Branch-and-bound interface routines" in a new edition of the
+        reference manual included in the distribution.
+
+GLPK 4.20 (release date: Jul 26, 2007)
+
+        API routine lpx_integer was replaced by API routine glp_intopt,
+        which provides equivalent functionality and additionally allows
+        the application to control the solution process by means of the
+        user-written callback routine, which is called by the solver at
+        various points of the branch-and-bound algorithm. Besides, the
+        new MIP solver allows generating "lazy" constraints and cutting
+        planes on all levels of the branch-and-bound tree, not only on
+        the root level. The routine lpx_integer is also still available
+        for the backward compatibility.
+
+        The following new advanced API routines, which may be called
+        from the B&B callback routine, were included in the package:
+
+        glp_ios_reason     determine reason for calling callback
+                           routine
+        glp_ios_get_prob   access the problem object
+        glp_ios_tree_size  determine size of the branch-and-bound tree
+        glp_ios_curr_node  determine current active subproblem
+        glp_ios_next_node  determine next active subproblem
+        glp_ios_prev_node  determine previous active subproblem
+        glp_ios_up_node    determine parent subproblem
+        glp_ios_node_level determine subproblem level
+        glp_ios_node_bound determine subproblem local bound
+        glp_ios_mip_gap    compute relative MIP gap
+        glp_ios_heur_sol   provide solution found by heuristic
+        glp_ios_terminate  terminate the solution process
+
+        For description of these routines see Chapter "Advanced API
+        routines", Section "Branch-and-bound interface routines" in a
+        new edition of the reference manual, which was included in the
+        distribution.
+
+        Old version of the integer optimization suite (IOS) as well as
+        TSP solver tspsol based on it are no longer supported and were
+        removed from the package.
+
+        A minor error in the MIP presolver was fixed; thanks to Graham
+        Rockwell <bionomicron@gmail.com> for the bug report.
+
+GLPK 4.19 (release date: Jul 05, 2007)
+
+        The principal change is upgrading to GPLv3.
+
+        A serious bug in the routine glp_del_cols was fixed; thanks to
+        Cedric[FR] <fox2113@wanadoo.fr> for the bug report. The bug
+        appeared because on deleting non-basic columns the basis header
+        remained valid, however, contained invalid (old) column ordinal
+        numbers.
+
+        A new advanced API routine glp_mem_limit was added.
+
+        The case GLP_EBOUND was added to the routine lpx_simplex.
+        Thanks to Cameron Kellough <Cameron.Kellough@sri.com> for the
+        bug report.
+
+        An API routine lpx_write_pb to write the problem instance in
+        OPB (pseudo boolean) format format was added. Thanks to Oscar
+        Gustafsson <oscarg@isy.liu.se> for the contribution.
+
+        Two new options --wpb and --wnpb were added to glpsol to write
+        the problem instance in OPB format.
+
+GLPK 4.18 (release date: Jun 25, 2007)
+
+        The following new API routines were added:
+
+        glp_set_rii        set (change) row scale factor
+        glp_set_sjj        set (change) column scale factor
+        glp_get_rii        retrieve row scale factor
+        glp_get_sjj        retrieve column scale factor
+        glp_simplex        solve LP problem with the simplex method
+                           (this routine replaces lpx_simplex, which is
+                           also available for backward compatibility)
+        glp_init_smcp      initialize simplex method control params
+        glp_bf_exists      check if the basis factorization exists
+        glp_factorize      compute the basis factorization
+        glp_bf_updated     check if the basis factorization has been
+                           updated
+        glp_get_bfcp       retrieve basis factorization control params
+        glp_set_bfcp       change basis factorization control params
+        glp_get_bhead      retrieve the basis header information
+        glp_get_row_bind   retrieve row index in the basis header
+        glp_get_col_bind   retrieve column index in the basis header
+        glp_ftran          perform forward transformation
+        glp_btran          perform backward transformation
+
+        For description of all these routines see a new edition of the
+        reference manual included in the distribution.
+
+        Type names ulong_t and uldiv_t were changed to glp_ulong and
+        glp_uldiv to avoid conflicts with standard type names on some
+        platforms. Thanks to Boris Wirtz <Boris.Wirtz@uni-oldenburg.de>
+        for the bug report.
+
+        Some new examples in the MathProg language were added. Thanks
+        to Sebastian Nowozin <nowozin@gmail.com>.
+
+GLPK 4.17 (release date: May 26, 2007)
+
+        API routines glp_set_mat_row, glp_set_mat_col, and glp_load_mat
+        were modified to allow zero constraint coefficients (which are
+        not stored in the constraint matrix). Note that constraint
+        coefficients with duplicate row/column indices are not allowed.
+
+        Another form of LP basis factorization was implemented in the
+        package. It is based on LU-factorization of an initial basis
+        and Schur complement to reflect changes in the basis. Currently
+        the implementation is incomplete and provides only updating the
+        factorization on replacing a column of the basis matrix. On API
+        level the user can set the control parameter LPX_K_BFTYPE to
+        choose between the folloiwng forms of LP basis factorization to
+        be used in the simplex method routines:
+        1) LU + Forrest-Tomlin update;
+        2) LU + Schur complement + Bartels-Golub update;
+        3) LU + Schur complement + Givens rotation update.
+        The GLPK implementation is similar to LUSOL/LUMOD developed by
+        Michael A. Saunders.
+
+        The user can choose the form of LP basis factorzation used by
+        the simplex method routines by specifying the folloiwng options
+        of glpsol: --luf, --cbg, --cgr.
+
+GLPK 4.16 (release date: May 05, 2007)
+
+        A number of basic GLPK API routines, which now are in the
+        stable stable, were renamed to be prefixed with 'glp_'. Note
+        that all these routines are available via their old names
+        prefixed with 'lpx_' that keeps the downward compatibility with
+        older versions of the package.
+
+        Three new GLPK API routines were added to the package:
+        glp_version, glp_term_hook, and glp_mem_usage; for more details
+        see a new edition of the GLPK reference manual included in the
+        distribution. The routine glp_version reports the actual version
+        of the GLPK library and also can be used (along with the header
+        glpk.h) in Autotools specification files to check if the GLPK
+        library has been installed.
+
+        The header glpk.h was changed to conform to C++ environment.
+
+GLPK 4.15 (release date: Feb 18, 2007)
+
+        Autotools specification files (configure.ac, Makefile.am) were
+        changed to use GNU Libtool. This allows building the static as
+        well as shared GLPK library.
+
+GLPK 4.14 (release date: Feb 05, 2007)
+
+        Now GLPK conforms to ILP32, LLP64, and LP64 programming models
+        (the latter seems to be the ultimate choice regarding 64-bit
+        architectures). Note that GLPK itself is a 32-bit application,
+        and the conformity only means that the package works correctly
+        on all these arenae. Nevertheless, on 64-bit platforms it is
+        possible to use more than 4GB of memory, if necessary.
+
+GLPK 4.13 (release date: Nov 13, 2006)
+
+        A tentative implementation of the "exact" simplex method based
+        on bignum (rational) arithmetic was included in the package.
+
+        On API level this new feature is available through the routine
+        lpx_exact, which is similar to the routine lpx_simplex.
+
+        In the solver glpsol this feature is available through two new
+        command-line options: --exact and --xcheck. If the '--exact'
+        option is specified, glpsol solves LP instance using the exact
+        simplex method; in case of MIP it is used to obtain optimal
+        solution of LP relaxation. If the --xcheck option is specified,
+        LP instance (or LP relaxation) is solved using the standard
+        (floating-point) simplex method, however, then glpsol calls the
+        exact simplex routine to make sure that the final LP basis is
+        exactly optimal, and if it is not, to perform some additional
+        simplex iterations in exact arithmetic.
+
+GLPK 4.12 (release date: Nov 08, 2006)
+
+        A tentative implementation of some simplex method routines
+        based on exact (bignum) arithmetic was included in the package.
+        Currently these routines provide computing LU-factorization of
+        the basis matrix and computing components of basic solution.
+
+        These routines were used to implement a routine, which checks
+        primal and dual feasibility of basic solution exactly, i.e. in
+        rational numbers, without round-off errors. In glpsol this
+        feature is available through the command-line option --xcheck.
+
+        GLPK has its own low-level routines implementing operations on
+        integer and rational numbers that makes it independent on other
+        software packages. However, to attain a much better performance
+        it is highly recommended to install (before configuring GLPK)
+        the GNU Multiple Precision Arithmetic Library (GMP). Using GMP
+        makes computations 100-200 times faster.
+
+GLPK 4.11 (release date: Jul 25, 2006)
+
+        Three new built-in functions in the modeling language were
+        implemented: card (cardinality of set), length (length of
+        character string), and substr (substring of character string).
+        Another improvement concerns the printf statement which now
+        allows redirecting its output to a specified file. These new
+        features are illustrated in example models crypto.mod and
+        graph.mod included in the distribution. For more details see
+        the document "Modeling Language GNU MathProg".
+
+        Four batch files (along with corresponding makefiles) were
+        included in the distribution to simplify building GLPK under
+        MS Windows; see them in subdirectory 'w32'.
+
+GLPK 4.10 (release date: May 11, 2006)
+
+        Cutting planes of two new classes were implemented: mixed cover
+        cuts and clique cuts. On API level this feature can be enabled
+        by setting control parameter LPX_K_USECUTS passed to the routine
+        lpx_intopt. In glpsol this feature is available through the
+        command-line options --cover and --clique. For more details see
+        the reference manual.
+
+        Now the routines lpx_read_mps and lpx_read_freemps support LI
+        bound type. It is similar to LO, however, indicates the column
+        as of integer kind.
+
+GLPK 4.9 (release date: Jan 17, 2006)
+
+        An advanced MIP solver was implemented. It includes:
+
+        - basic presolving technique (removing free, singleton and
+          redundant rows, improving bounds of columns, removing fixed
+          columns, reducing constraint coefficents);
+
+        - generating cutting planes to improve LP relaxation (currently
+          only Gomory's mixed integer cuts are implemented);
+
+        - using the branch-and-bound method to solve resultant MIP;
+
+        - recovering solution of the original MIP.
+
+        The solver is available on API level via the routine lpx_intopt
+        (see the reference manual). It is similar to the routine
+        lpx_integer, however, does not require initial solution of LP
+        relaxation.
+
+        The solver is also available in the command-line utility glpsol
+        via two options: --intopt (only presolving) and --cuts (assumes
+        --intopt plus generating cuts).
+
+        Note that efficiency of the MIP solver strongly depends on the
+        internal structure of the problem to be solved. For some hard
+        instances it is very efficient, but for other instances it may
+        be significantly worse than the standard branch-and-bound.
+
+        For some comparative benchmarks see doc/bench1.txt.
+
+        Well, what else...
+
+        Three built-in functions were added to MathProg: sin, cos, and
+        atan (the latter allows one or two arguments).
+
+        Some bugs were fixed.
+
+        Several new examples in MathProg were included: color.mod
+        (graph coloring problem), tsp.mod (traveling salesman problem),
+        and pbn.mod (paint-by-numbers puzzle).
+
+GLPK 4.8 (release date: Jan 12, 2005)
+
+        Core simplex method and interior-point method routines were
+        re-implemented and now they use a new, "storage-by-rows" sparse
+        matrix format (unlike previous versions where linked lists were
+        used to represent sparse matrices). For details see ChangeLog.
+
+        Also a minor bug was fixed in API routine lpx_read_cpxlp.
+
+GLPK 4.7 (release date: Aug 23, 2004)
+
+        Now GLPK supports free MPS format. Two new API routines
+        lpx_read_freemps (to read problem data in free MPS format) and
+        lpx_write_freemps (to write problem data in free MPS format)
+        were added. This feature is also available in the solver glpsol
+        via new command-line options --freemps and --wfreemps. For more
+        details see the GLPK reference manual.
+
+        API routines lpx_read_cpxlp and lpx_write_cpxlp for reading and
+        writing problem data in CPLEX LP format were re-implemented to
+        allow long symbolic names (up to 255 characters).
+
+        The following three modules were temporarily removed from the
+        GLPK distribution due to licensing problems: DELI (an interface
+        module to Delphi), GLPKMEX (an interface module to Matlab), and
+        JNI (an interface module to Java).
+
+GLPK 4.6 (release date: Aug 04, 2004)
+
+        Three new statements were implemented in the GNU MathProg
+        language: solve, printf, and for. Their detailed description can
+        be found in the GLPK documentation included in the distribution.
+        (See also a sample model, examples/queens.mod, which illustrates
+        using these new statements.)
+
+        Two new API routines were added to the package: lpx_read_prob
+        and lpx_write_prob. They allow reading/writing problem data in
+        GNU LP low-level text format.
+
+        Three new command-line options were implemented in the LP/MIP
+        solver glpsol: --glp (to read problem data in GNU LP format),
+        --wglp (to write problem data in GNU LP format), and --name (to
+        change problem name). Now glpsol also supports processing models
+        where the new statements (see above) are used.
+
+        A new version of GLPKMEX, a Matlab MEX interface to GLPK, was
+        included. For more details see contrib/glpkmex/ChangeLog.
+
+GLPK 4.5 (release date: Jul 19, 2004)
+
+        The branch-and-bound solver was completely re-implemented.
+
+        Some modifications were made in memory allocation routines that
+        allows using the package on 64-bit platforms.
+
+        For more details see ChangeLog.
+
+GLPK 4.4 (release date: Jan 17, 2004)
+
+        All API routines were re-implemented using new data structures.
+        The new implementation provides the same specifications and
+        functionality of API routines as the old one, however, it has
+        some important advantages, in particular:
+        * linked lists are used everywhere that allows creating and
+          modifying the problem object as efficiently as possible
+        * all data stored in the problem object are non-scaled (even if
+          the internal scaling is used) that prevents distortion of the
+          original problem data
+        * solution components obtained by the solver remain available
+          even if the problem object has been modified
+        * no solver-specific data are used in the new data structures
+          that allows attaching any external lp/mip solver using GLPK
+          API as an uniform interface
+        Note that some API routines became obsolete being replaced by
+        new, more convenient routines. These obsolete routines are kept
+        for backward compatibility, however, they will be removed in
+        the future. For more details please see ChangeLog and the GLPK
+        Reference Manual.
+
+        New edition of the GLPK Reference Manual was included in the
+        distribution.
+
+        GLPKMEX, a Matlab MEX interface to GLPK package, contributed by
+        Nicolo Giorgetti <giorgetti@dii.unisi.it> was included in the
+        distribution.
+
+        GLPK FAQ contributed by Harley Mackenzie <hjm@bigpond.com> was
+        included in the distribution.
+
+GLPK 4.3 (release date: Dec 12, 2003)
+
+        The bug, due to which the standard math library is not linked
+        on building the package on some platforms, was fixed.
+
+        The following new built-in functions were added to the MathProg
+        language: round, trunc, Irand224, Uniform01, Uniform, Normal01,
+        Normal. For details see the language description.
+
+        The MathProg syntax was changed to allow writing 'subj to' that
+        means 'subject to'.
+
+        The new api routine lpx_get_ray_info was added. It is intended
+        to determine which (non-basic) variable causes unboundness. For
+        details see the reference manual.
+
+        The module glpmps.c was changed to avoid compilation errors on
+        building the package on Mac OS X.
+
+        Several typos was fixed and some new material was added to the
+        GLPK documentation.
+
+GLPK 4.2 (release date: Nov 14, 2003)
+
+        A preliminary implementation of the Integer Optimization Suite
+        (IOS) was included in the package. The Branch-and-Cut Framework
+        being completely superseded by IOS was removed from the package.
+
+        New API routine lpx_print_sens_bnds intended for bounds
+        sensitivity analysis was contributed to GLPK by Brady Hunsaker
+        <hunsaker@engr.pitt.edu>. This function is also available in
+        the solver glpsol (via command-line option --bounds).
+
+        An improved version of GLPK JNI (Java Native Interface) was
+        contributed by Chris Rosebrugh <cpr@pobox.com>.
+
+        GLPK DELI (Delphi Interface) was contributed by Ivo van Baren
+        <i.van.baren@freeler.nl>.
+
+        Several makefiles were added to allow compiling GLPK on some
+        non-GNU 32-bit platforms:
+        * Windows single-threaded static library, Visual C++ 6.0
+        * Windows multi-threaded dynamic library, Visual C++ 6.0
+        * Windows single-threaded static library, Borland C++ 5.2
+        * DOS single-threaded static library, Digital Mars C++ 7.50
+
+        And, of course, some bugs were fixed.
+
+        For more details see ChangeLog.
+
+GLPK 4.1 (release date: Aug 23, 2003)
+
+        Some improvements were made in the lp/mip solver routines and
+        several bugs were fixed in the model translator.
+
+        For more details see ChangeLog.
+
+GLPK 4.0 (release date: May 06, 2003)
+
+        Now GLPK supports the GNU MathProg modeling language, which is
+        a subset of the AMPL modeling language.
+
+        The document "GLPK: Modeling Language GNU MathProg" included in
+        the distribution is a complete description of GNU MathProg. (See
+        the files lang.latex, lang.dvi, and lang.ps in the subdirectory
+        'doc'. See also some examples in the subdirectory 'sample'.)
+
+        New version of the solver glpsol, which supports models written
+        in GNU MathProg, was implemented. (Brief instructions how to use
+        glpsol can be found in the GNU MathProg documentation.)
+
+        The GLPK/L modeling language is no more supported. The reason is
+        that GNU MathProg being much more powerful completely supersedes
+        all features of GLPK/L.
+
+GLPK 3.3 (release date: Mar 25, 2003)
+
+        LP PRESOLVER
+        ------------
+
+        Now the routine lpx_simplex (which is a driver to the simplex
+        method for solving LP) is provided with the built-in LP
+        presolver, which is a program that transforms the original LP
+        problem to an equivalent LP problem, which may be easier for
+        solving with the simplex method than the original one. Once the
+        transformed LP has been solver, the presolver transforms its
+        basic solution back to a corresponding basic solution of the
+        original problem. For details about this feature please see the
+        GLPK reference manual.
+
+        Currently the LP presolver implements the following features:
+        * removing empty rows;
+        * removing empty columns;
+        * removing free rows;
+        * removing fixed columns;
+        * removing row singletons, which have the form of equations;
+        * removing row singletons, which have the form of inequalities;
+        * removing column singletons, which are implied slack variables;
+        * fixing and removing column singletons, which are implied free
+          variables;
+        * removing forcing rows that involves fixing and removing the
+          corresponding columns;
+        * checking for primal and dual infeasibilities.
+
+        The LP presolver is also used by default in the stand-alone
+        program glpsol. In order *not* to use it, the option --nopresol
+        should be specified in the command-line.
+
+        CHANGES IN GLPK/L
+        -----------------
+
+        The syntax and semantics of the GLPK/L modeling language was
+        changed to allow declaration of "interval" sets. This means that
+        now the user can declare a set, for example, as:
+
+           set task = [8:11];
+
+        that is exactly equivalent to the following declaration:
+
+           set task = (task_8, task_9, task_10, task_11);
+
+        For details see the language description.
+
+        JAVA INTERFACE
+        --------------
+
+        Now GLPK includes the package GLPK JNI (Java Native Interface)
+        that implements Java binding for GLPK. It allows Java programs
+        to utilize GLPK in solving LP and MIP problems. For details see
+        a brief user's guide in the subdirectory contrib/java-binding.
+        This package was developed and programmed by Yuri Victorovich
+        <yuri@gjt.org>, who contributed it to GLPK.
+
+GLPK 3.2.4 (release date: Feb 18, 2003)
+
+        This is a bug-fix release. For details see ChangeLog.
+
+GLPK 3.2.3 (release date: Nov 11, 2002)
+
+        A new implementation of the api routine lpx_integer which now
+        is based on the b&b driver (which is based on the implicit
+        enumeration suite) was included in the package. This new
+        implementation has exactly the same functionality as the old
+        version, so all changes are transparent to the api user.
+
+        Four new api routines were included in the package:
+        lpx_check_kkt checks Karush-Kuhn-Tucker optmality conditions;
+        lpx_read_bas reads predifined basis in MPS format;
+        lpx_write_bas writes current basis in MPS format;
+        lpx_write_lpt writes problem data in CPLEX LP format.
+
+        Also other minor improvements were made (for details see the
+        file 'ChangeLog').
+
+GLPK 3.2.2 (release date: Oct 14, 2002)
+
+        The api routine lpx_read_lpt was included in the package. It
+        is similar to the routine lpx_read_mps and intended to read
+        LP/MIP data prepared in CPLEX LP format. Description of this
+        format is given in the GLPK reference manual, a new edition of
+        which was also included in the distribution (see the files
+        'refman.latex', 'refman.dvi', 'refman.ps' in the subdirectory
+        'doc'). In order to use data files in CPLEX LP format with the
+        solver glpsol the option '--lpt' should be specified in the
+        command line.
+
+        Several bugs were fixed and some minor improvements were made
+        (for details see the file 'ChangeLog').
+
+GLPK 3.2.1 (release date: Aug 12, 2002)
+
+        Now GLPK includes a preliminary implementation of the
+        branch-and-cut framework, which is a set of data structures and
+        routines intended for developing branch-and-cut methods for
+        solving mixed-integer and combinatorial optimization problems.
+
+        Detailed decsription of the branch-and-cut framework is given in
+        the document "GLPK: A Preliminary Implementation of the
+        Branch-And-Cut Framework" included in the distribution (see the
+        file 'brcut.txt' in the subdirectory 'doc').
+
+        In order to illustrate how the GLPK branch-and-cut framework
+        can be used for solving a particular optimization problem there
+        is an example included in the package. This is a stand-alone
+        program, TSPSOL, which is intended for solving to optimality the
+        symmetric Traveling Salesman Problem (TSP), a classical problem
+        of the combinatorial optimization (see the file 'tspsol.c' in
+        the subdirectory 'sample').
+
+GLPK 3.2 (release date: Jul 15, 2002)
+
+        New edition of the document "GLPK: Reference Manual" was
+        included (see the files 'refman.latex', 'refman.dvi', and
+        'refman.ps' in the subdirectory 'doc').
+
+        New edition of the document "GLPK: Modeling Language GLPK/L" was
+        included (see the files 'lang.latex', 'lang.dvi', and 'lang.ps'
+        in the subdirectory 'doc').
+
+        The following new API routines were added to the package:
+
+        lpx_transform_row (transform explicitly specified row);
+        lpx_transform_col (transform explicitly specified column);
+        lpx_prim_ratio_test (perform primal ratio test);
+        lpx_dual_ratio_test (perform dual ratio test);
+        lpx_interior (solve LP problem using interior point method);
+        lpx_get_ips_stat (query status of interior point solution);
+        lpx_get_ips_row (obtain row interior point solution);
+        lpx_get_ips_col (obtain column interior point solution);
+        lpx_get_ips_obj (obtain interior point value of obj.func.);
+        lpx_read_lpm (read LP/MIP model written in GLPK/L);
+        lpx_write_mps (write problem data using MPS format);
+        lpx_print_ips (print interior point solution).
+
+        Detailed description of all these new API routines are given in
+        the new edition of the reference manual.
+
+        New version of the stand-alone solver glpsol (which is based on
+        the new API) was implemented.
+
+        So long as the new API (introduced in glpk 3.0) now provides
+        all the functions, which were provided by the old API, the old
+        API routines were removed from the package at all.
+
+GLPK 3.1 (release date: May 27, 2002)
+
+        A preliminary implementation of new API routines was completed
+        and included in the package.
+
+        These new API routines provide much more flexible interaction
+        between the application program, LP/MIP problem instances, and
+        solver routines. Based on completely changed data structures
+        they are, however, similar to the API routines and provide the
+        same functionality. Please note that three routines, namely,
+        solving LPs using interior point method, reading model written
+        in the GLPK/L modeling language, and writing problem data in
+        the MPS format, are not implemented in the new API, however,
+        these routines are planned to be implemented in the next version
+        of the package.
+
+        A description of the new API routines is given in the document
+        "GLPK Reference Manual", a draft edition of which is included
+        in the package (see the files 'refman.latex', 'refman.dvi', and
+        'refman.ps' in the subdirectory 'doc').
+
+        Although the old API routines are kept in the package, they are
+        no longer supported and will be removed in the future.
+
+GLPK 3.0.8 (release date: May 13, 2002)
+
+        A preliminary implementation of new API routines was included
+        in the package. These new API routines are intended to provide
+        much more flexible interaction between the application program,
+        LP/MIP problem and solver routines. See the document "New GLPK
+        API Routines" (the file 'newapi.txt' in the subdirectory 'doc')
+        also included in the package.
+
+        The api routines glp_simplex2, glp_call_ipm1, glp_call_bbm1 were
+        renamed, respectively, to glp_simplex, glp_interior, glp_integer
+        in order to reflect changes in implementation. The api routines
+        glp_call_rsm1, glp_simplex1, glp_pivot_in, glp_pivout_out were
+        removed from the package since they are completely supreseded by
+        the new API routines (however, these routines still can be found
+        in the subdirectory 'oldsrc'). Please consult a new edition of
+        the document "GLPK User's Guide" about all these changes in the
+        existing api routines.
+
+        The document "GLPK Library Reference" was removed from the
+        package (into the subdirectory 'oldsrc') since it describes the
+        obsolete library routines, most of which are no longer used.
+
+GLPK 3.0.7 (release date: Apr 22, 2002)
+
+        A new, more efficient implementation of the primal/dual simplex
+        method was included in the package. Due to some improvements the
+        simplex-based solver allows solving many LP problems faster and
+        provides more reliable results. Note that the new implementation
+        is currently incomplete and available only via the api routine
+        glp_simplex2.
+
+        All the changes are transparent on API level.
+
+GLPK 3.0.6 (release date: Mar 28, 2002)
+
+        New version of LU-factorization and basis maintenance routines
+        (based on Forrest-Tomlin updating technique) was implemented.
+        Since these new routines functionally supersede some routines
+        (which implement other forms of the basis matrix) and make them
+        obsolete, the latter were removed from the package (they still
+        can be found in the subdirectory 'oldsrc').
+
+        All the changes are transparent on API level.
+
+GLPK 3.0.5 (release date: Jan 29, 2002)
+
+        New edition of the document "GLPK User's Guide" was included in
+        the distribution. Now it describes all additional API routines,
+        which were recently added to the package.
+
+        Structure of the package was re-organized in order to make its
+        maintenance easier (all small files in the subdurectory 'source'
+        were merged in bigger units). These changes are transparent for
+        the user.
+
+GLPK 3.0.4 (release date: Dec 10, 2001)
+
+        A new, more efficient implementation of the two-phase primal
+        simplex method was included in the package. Due to some new
+        features (an advanced initial basis, projected steepest edge,
+        recursive updating values and reduced costs) the new LP solver
+        is faster and numerically more stable than the old one.
+
+        The new LP solver is available as API routine glp_simplex2 and
+        has the same purpose as API routine glp_call_rsm1. For detailed
+        specification see the file 'newapi.txt' in the directory 'doc'.
+
+        Now the new LP solver is also used by default to solve an
+        initial LP problem in the branch-and-bound routine glp_call_bbm1
+        instead the routine rsm1_driver. Note that the branch-and-bound
+        procedure itself is still based on rsm1_driver.
+
+        The new LP solver is also used as default solver in GLPSOL for
+        solving LP and MIP problems. In order to choose the old solver
+        the option '--old-sim' can be specified in the command line.
+
+GLPK 3.0.3 (release date: Oct 03, 2001)
+
+        Some minor changes were made in the simplex method routines in
+        order to improve numerical stability of the method.
+
+GLPK 3.0.2 (release date: Sep 24, 2001)
+
+        A new implementation of the basis maintaining routines was
+        included in the package. These routines, which are based on so
+        called FHV-factorization (a variety of LU-factorization) of the
+        basis matrix and Gustavson's data structures, allows performing
+        the main operations faster at the expense of some worsening
+        numerical accuracy.
+
+        AFI (Advanced Form of the Inverse), which is the form of the
+        basis matrix based on FHV-factorization, is available via the
+        parameter form = 3 (on API level) or via the option --afi (in
+        GLPSOL solver).
+
+GLPK 3.0.1 (release date: Aug 01, 2001)
+
+        Old GLPK API routines have been removed from the package.
+
+        New GLPK API routines were added:
+
+        - scaling routines;
+
+        - a routine for writing problem data in MPS format;
+
+        - a comprehensive driver to the simplex method;
+
+        - basis maintaining routines.
+
+        A description of the new API routines is given in the document
+        "Additional GLPK API Routines". This document is included into
+        the distribution in plain text format (see the file 'newapi.txt'
+        in the subdirectory 'doc').
+
+        Now the distribution includes a non-trivial example of using
+        GLPK as a base LP solver for Concorde, a well known program that
+        solves Traveling Salesman Problem (TSP). For further details see
+        comments in the file 'sample/lpglpk30.c'.
+
+GLPK 3.0 (release date: Jul 19, 2001)
+
+        Now GLPK is provided with new API, which being more flexible
+        can be used in more complex algorithmic schemes.
+
+        New edition of the document "GLPK User's Guide" is included in
+        the distribution. Now it completely corresponds to the new GLPK
+        API routines.
+
+        Old API routines are not removed yet from the package, however
+        they became obsolete and therefore should not be used. Since now
+        the header glpk.h corresponds to new API, in order to compile
+        existing programs that use old GLPK API routines the statement
+
+        #define GLP_OLD_API
+
+        should be inserted before the statement
+
+        #include "glpk.h"
+
+GLPK 2.4.1 (release date: Jun 14, 2001)
+
+        The document "Modeling language GLPK/L" is included into the
+        distribution in texinfo format.
+
+        New edition of the document "GLPK User's Guide" is included in
+        the distribution. Now it describes all additional API routines
+        which were recently added to the package.
+
+GLPK 2.4 (release date: May 10, 2001)
+
+        Now GLPK includes an implementation of a preliminary version
+        of the GLPK/L modeling language. This language is intended for
+        writing mathematcal programming models. The name GLPK/L is
+        derived from GNU Linear Programming Kit Language.
+
+        A brief description of the GLPK/L language is given in the
+        document "GLPK/L Modeling Language: A Brief Description". This
+        document is included into the distribution in plain text format
+        (see the file 'language.txt' in the subdirectory 'doc').
+
+        The language processor (which is a program that analyzes model
+        description written in GLPK/L and translates it to internal data
+        structures) is available as the GLPK API routine.
+
+        The stand-alone solver GLPSOL now is able: a) to process model
+        descriptions written in the GLPK/L language; b) to solve pure LP
+        problems using the interior point method (therefore the program
+        GLPIPM was removed from the package).
+
+GLPK 2.3 (release date: Apr 09, 2001)
+
+        New edition of the document "GLPK User's Guide" is included in
+        the distribution. Now it describes all additional API routines
+        which were recently added to the package.
+
+        The MIP solver was fully re-programmed in order to improve its
+        robustness and performance. In particular, a basis recovering
+        procedure was implemented (this procedure allows switching to
+        the primal simplex method in case when the dual simplex method
+        fails).
+
+GLPK 2.2 (release date: Mar 15, 2001)
+
+        Now GLPK includes a tentative implementation of the
+        branch-and-bound procedure based on the dual simplex method for
+        mixed integer linear programming (MIP).
+
+        Complete description of this new feature of the package is given
+        in the preliminary document "Mixed Integer Linear Programming
+        Using GLPK Version 2.2 (Supplement to GLPK User's Guide)". This
+        document is included into the distribution in plain text format
+        (see the file 'mip.txt' in the subdirectory 'doc').
+
+        The MIP solver (glp_integer) can be used as GLPK API routine in
+        the same way as the pure LP solver (glp_simplex).
+
+        The stand-alone program 'glpsol' is now able to solve LP as well
+        as MIP problems.
+
+        Note that the current version of GLPK MIP solver is based on
+        easiest heuristics for branching and backtrackng. Therefore the
+        solver is fit mainly for MIP problems which are not very hard
+        and have few integer variables.
+
+GLPK 2.1 (release date: Feb 19, 2001)
+
+        The document "GLPK Implementation of the Revised Simplex Method"
+        is included into the distribution. This document describes most
+        of routines related to the revised simplex method.
+
+GLPK 2.0 (release date: Jan 25, 2001)
+
+        Now GLPK includes a tentative implementation of the primal-dual
+        interior point method for large-scale linear programming.
+
+        The interior point solver can be used as GLPK API routine in the
+        same manner as the simplex method solver (glp_simplex):
+
+        ret = glp_interior();
+
+        Note that currently the interior point solver implemented in
+        GLPK doesn't include many important features, in particular:
+
+        * it can't process dense columns; therefore if the problem has
+          dense columns, the solving will be extremely inefficient;
+
+        * it has no special features against numerical unstability;
+          some problems may cause premature termination of the solving
+          when the matrix A*D*A' becomes ill-conditioned;
+
+        * it computes only values of primal (auxiliary and structural)
+          variables and doesn't compute values of dual variables (i.e.
+          reduced costs) which are just set to zero;
+
+        * it doesn't identify optimal basis corresponding to the found
+          interior point solution; all variables in the found solution
+          are just marked as basic variables.
+
+        GLPK also includes a stand-alone program 'glpipm' which is a
+        demo based on the interior point method. It may be used in the
+        same way as the program 'glpsol' that is based on the simplex
+        method.
Index: deps/glpk/README
===================================================================
--- deps/glpk/README	(revision 9)
+++ deps/glpk/README	(revision 9)
@@ -0,0 +1,39 @@
+                                                     Olga K. gewidmet
+
+GLPK (GNU Linear Programming Kit) Version 4.47
+
+Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+E-mail: <mao@gnu.org>.
+
+GLPK is part of the GNU Project released under the aegis of GNU.
+
+GLPK is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+See the file COPYING for the GNU General Public License.
+
+See the file INSTALL for compilation and installation instructions.
+
+The GLPK package is a set of routines written in ANSI C and organized
+in the form of a callable library. This package is intended for solving
+large-scale linear programming (LP), mixed integer linear programming
+(MIP), and other related problems.
+
+The GLPK package includes the following main components:
+
+* implementation of the simplex method;
+* implementation of the exact simplex method based on bignum (rational)
+  arithmetic;
+* implementation of the primal-dual interior-point method;
+* implementation of the branch-and-cut method;
+* application program interface (API);
+* GNU MathProg modeling language (a subset of AMPL);
+* GLPSOL, a stand-alone LP/MIP solver.
+
+See GLPK webpage <http://www.gnu.org/software/glpk/glpk.html>.
+
+Please report bugs to <bug-glpk@gnu.org>.
Index: deps/glpk/THANKS
===================================================================
--- deps/glpk/THANKS	(revision 9)
+++ deps/glpk/THANKS	(revision 9)
@@ -0,0 +1,185 @@
+Marco Atzeri <marco.atzeri@gmail.com> for buf report.
+
+Noli Sicad <nsicad@gmail.com> for testing glpk under Mac OS.
+
+Pietro Scionti <pietro.scionti@archinet.it> for report typos found in
+the reference manual.
+
+Noli Sicad <nsicad@gmail.com> for example model in MathProg.
+
+Nigel Galloway <nigel_galloway@operamail.com> for example model in
+MathProg.
+
+Xypron <xypron.glpk@gmx.de> for contribution and testing batch scripts
+to build Glpk with MS Visual Studio 2010.
+
+Xypron <xypron.glpk@gmx.de> for improving the SQL table driver.
+
+Stefan Vigerske <stefan@math.hu-berlin.de> for bug report.
+
+Uday Venkatadri <Uday.Venkatadri@dal.ca> for bug report.
+
+Xypron <xypron.glpk@gmx.de> for bug fixing and some improvments in the
+FPUMP module.
+
+Niels Klitgord <niels@bu.edu> for bug report.
+
+Thomas Kahle <tom111@gmx.de> for some suggestions.
+
+Jonathan Senning <Jonathan.Senning@gordon.edu> for bug report.
+
+Xypron <xypron.glpk@gmx.de> for testing GLPK on 64-bit platforms and
+for maintaining Windows versions of the package.
+
+Nelson H. F. Beebe <beebe@math.utah.edu> for bug report.
+
+Larry D'Agostino <Larry.D'Agostino@gmacrescap.com> for example model in
+MathProg.
+
+Marco Atzeri <marco_atzeri@yahoo.it> for bug report.
+
+Robert Wood <rgwood01@cox.net> for example model in MathProg.
+
+Sebastien Briais <sbriais@free.fr> for bug report.
+
+Kelly Westbrooks <kellywestbrooks@yahoo.com> for suggestions.
+
+Nigel Galloway <nigel_galloway@operamail.com> for example models in
+MathProg.
+
+Xypron <xypron.glpk@gmx.de> for bug patch.
+
+Sebastian Nowozin <nowozin@gmail.com> for example models in MathProg.
+
+Stefan Vigerske <stefan@vigerske.de> for bug report.
+
+Luiz Bettoni <bettoni@cpgei.ct.utfpr.edu.br> for some suggestions.
+
+Nigel Galloway <nigel_galloway@operamail.com> for bug report.
+
+Peter Ingerfeld <peter.ingerfeld@mops-optimizer.com> for bug report.
+
+Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for contribution of
+makefiles and testing the package under 64-bit Windows. 
+
+Oscar Gustafsson <oscarg@isy.liu.se> for contribution of a new version
+of the routine to write data in OPB (pseudo boolean) format.
+
+Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for some patches for
+the MathProg translator.
+
+Markus Pilz <pilz@cs.uni-bonn.de> for bug report.
+
+Anne-Laurence Putz <anne-laurence.putz@eurodecision.com> for bug
+report.
+
+Robbie Morrison <robbie@actrix.co.nz> for correcting the glpk manual.
+
+Axel Simon <Axel.Simon@ens.fr> for bug report.
+
+Vijay Patil <vijay.patil@gmail.com> for testing the package under
+Windows XP.
+
+Heinrich Schuchardt <heinrich.schuchardt@gmx.de> for contribution of
+two MathProg table drivers for iODBC and MySQL.
+
+Rafael Laboissiere <rafael@debian.org> for useful advices concerning
+shared library support under GNU/Linux.
+
+Nigel Galloway <Nigel_Galloway@operamail.com> for an example program
+in C#.
+
+Enric Rodriguez <erodri@lsi.upc.edu> for bug report.
+
+Nigel Galloway <Nigel_Galloway@operamail.com> for an example MathProg
+model.
+
+Roberto Bagnara <bagnara@cs.unipr.it> (Department of Mathematics,
+University of Parma, Italy) for bug report.
+
+Peter T. Breuer <ptb@inv.it.uc3m.es> for bug report.
+
+Graham Rockwell <bionomicron@gmail.com> for bug report.
+
+Cedric[FR] <fox2113@wanadoo.fr> for bug report.
+
+Cameron Kellough <Cameron.Kellough@sri.com> for bug report.
+
+Oscar Gustafsson <oscarg@isy.liu.se> for contribution of a routine to
+write data in OPB (pseudo boolean) format.
+
+Boris Wirtz <Boris.Wirtz@uni-oldenburg.de> for bug report.
+
+Sebastian Nowozin <nowozin@gmail.com> for three example MathProg
+models.
+
+Rafael Laboissiere <rafael@debian.org> for useful advices concerning
+shared library support.
+
+Dr. Harley Mackenzie <hjm@hardsoftware.com> for two example MathProg
+models (curve fitting problem).
+
+Minh Ha Duong <haduong@centre-cired.fr> for fixing doc typos.
+
+Brady Hunsaker <hunsaker@engr.pitt.edu> for some suggestions concerning
+MIP routines.
+
+Karel Zimmermann <kzimm@diamant.jouy.inra.fr> for bug report.
+
+Christophe Caron <caron@diamant.jouy.inra.fr> for bug report.
+
+Nicolo Giorgetti <giorgetti@dii.unisi.it> for contribution of GLPKMEX,
+a Matlab MEX interface.
+
+Harley Mackenzie <hjm@bigpond.com> for contribution of GLPK FAQ.
+
+Andre Girard <andre@inrs-emt.uquebec.ca> for bug report.
+
+Morten Welinder <terra@gnu.org> for bug report.
+
+Brady Hunsaker <hunsaker@engr.pitt.edu> for contribution of a routine
+for bounds sensitivity analysis.
+
+Chris Rosebrugh <cpr@pobox.com> for contribution of a new version of
+GLPK JNI (Java Native Interface).
+
+Ivo van Baren <i.van.baren@freeler.nl> for contribution of GLPK DELI
+(Delphi Interface).
+
+Andrew Hamilton-Wright <andrewhw@ieee.org> for bug report.
+
+Jiri Spitz <jiri.spitz@telecom.cz> for bug report.
+
+Giles Thompson <gwpt1@cus.cam.ac.uk> for bug report.
+
+Sebastien de Menten <sdementen@hotmail.com> for bug report.
+
+Kendall Demaree <kendal.demaree@verizon.net> for bug report.
+
+Bernhard Schmidt <schmidt@math.uni-augsburg.de> for bug report.
+
+Yuri Victorovich <yuri@gjt.org> for contribution of GLPK Java binding.
+
+Olivier <odwl@skynet.be> for bug report.
+
+Kjell Eikland <kjell.eikland@broadpark.no> for bug report.
+
+Ivan Luzzi <iluzzi@libero.it> for comments concerning CPLEX LP format.
+
+Peter Lee <plee@kinggee.com.au> for example LP model and bug report.
+
+Morten Welinder <terra@diku.dk> for bug report.
+
+Vlahos Kiriakos <Kiriakos.Vlahos@gs.com> for bug report.
+
+Flavio Keidi Miyazawa <fkm@ic.unicamp.br> for bug report.
+
+Hans Schwengeler <Hans.Schwengeler@unibas.ch> for bug report.
+
+Sami Farin <sfarin@ratol.fi> for bug report.
+
+Peter A. Huegler <phuegler@bsco.com> for bug report.
+
+Alexandre Oliva <oliva@lsd.ic.unicamp.br> for bug report.
+
+Andrew Hood <ajhood@fl.net.au> for bug report.
Index: deps/glpk/aclocal.m4
===================================================================
--- deps/glpk/aclocal.m4	(revision 9)
+++ deps/glpk/aclocal.m4	(revision 9)
@@ -0,0 +1,956 @@
+# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],,
+[m4_warning([this file was generated for autoconf 2.65.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.11.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+	[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 10
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], UPC,  [depcc="$UPC"  am_compiler_list=],
+       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                   [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named `Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running `make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES(CC)],
+		  [define([AC_PROG_CC],
+			  defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES(CXX)],
+		  [define([AC_PROG_CXX],
+			  defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES(OBJC)],
+		  [define([AC_PROG_OBJC],
+			  defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p.  We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+  [[\\/$]]* | ?:[[\\/]]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+   if test "$[*]" = "X"; then
+      # -L didn't work.
+      set X `ls -t "$srcdir/configure" conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$[*]" != "X $srcdir/configure conftest.file" \
+      && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+     [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+     [m4_case([$1], [ustar],, [pax],,
+              [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+  case $_am_tool in
+  gnutar)
+    for _am_tar in tar gnutar gtar;
+    do
+      AM_RUN_LOG([$_am_tar --version]) && break
+    done
+    am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+    am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+    am__untar="$_am_tar -xf -"
+    ;;
+  plaintar)
+    # Must skip GNU tar: if it does not support --format= it doesn't create
+    # ustar tarball either.
+    (tar --version) >/dev/null 2>&1 && continue
+    am__tar='tar chf - "$$tardir"'
+    am__tar_='tar chf - "$tardir"'
+    am__untar='tar xf -'
+    ;;
+  pax)
+    am__tar='pax -L -x $1 -w "$$tardir"'
+    am__tar_='pax -L -x $1 -w "$tardir"'
+    am__untar='pax -r'
+    ;;
+  cpio)
+    am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+    am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+    am__untar='cpio -i -H $1 -d'
+    ;;
+  none)
+    am__tar=false
+    am__tar_=false
+    am__untar=false
+    ;;
+  esac
+
+  # If the value was cached, stop now.  We just wanted to have am__tar
+  # and am__untar set.
+  test -n "${am_cv_prog_tar_$1}" && break
+
+  # tar/untar a dummy directory, and stop if the command works
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  echo GrepMe > conftest.dir/file
+  AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+  rm -rf conftest.dir
+  if test -s conftest.tar; then
+    AM_RUN_LOG([$am__untar <conftest.tar])
+    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+  fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
Index: deps/glpk/config.guess
===================================================================
--- deps/glpk/config.guess	(revision 9)
+++ deps/glpk/config.guess	(revision 9)
@@ -0,0 +1,1501 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	LIBC=gnu
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    i386)
+		eval $set_cc_for_build
+		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		      grep IS_64BIT_ARCH >/dev/null
+		  then
+		      UNAME_PROCESSOR="x86_64"
+		  fi
+		fi ;;
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Index: deps/glpk/config.h.in
===================================================================
--- deps/glpk/config.h.in	(revision 9)
+++ deps/glpk/config.h.in	(revision 9)
@@ -0,0 +1,27 @@
+/* config.h.in (GLPK configuration template file) */
+
+#undef HAVE_SYS_TIME_H
+/* defined if the <sys/time.h> header can be used */
+
+#undef HAVE_GETTIMEOFDAY
+/* defined if the gettimeofday function can be used */
+
+#undef HAVE_GMP
+/* defined if the GNU MP bignum library is available */
+/* requires <gmp.h> and -lgmp */
+
+#undef HAVE_LTDL
+/* defined if the GNU Libtool shared library support is enabled */
+/* requires <ltdl.h> and -lltdl */
+
+#undef HAVE_DLFCN
+/* defined if the POSIX shared library support is enabled */
+/* requires <dlfcn.h> */
+
+#undef ODBC_DLNAME
+/* ODBC shared library name if this feature is enabled */
+
+#undef MYSQL_DLNAME
+/* MySQL shared library name if this feature is enabled */
+
+/* eof */
Index: deps/glpk/config.sub
===================================================================
--- deps/glpk/config.sub	(revision 9)
+++ deps/glpk/config.sub	(revision 9)
@@ -0,0 +1,1705 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze)
+		os=
+		basic_machine=$1
+		;;
+        -bluegene*)
+	        os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+        microblaze)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+        -auroraux)
+	        os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Index: deps/glpk/configure
===================================================================
--- deps/glpk/configure	(revision 9)
+++ deps/glpk/configure	(revision 9)
@@ -0,0 +1,13297 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.65 for GLPK 4.47.
+#
+# Report bugs to <bug-glpk@gnu.org>.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+	# neutralization value for shells without unset; and this also
+	# works around shells that cannot unset nonexistent variables.
+	BASH_ENV=/dev/null
+	ENV=/dev/null
+	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+	export CONFIG_SHELL
+	exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and bug-glpk@gnu.org
+$0: about your system, including any error possibly output
+$0: before this message. Then install a modern shell, or
+$0: manually run the script under such a shell if you do
+$0: have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$?; test $as_status -eq 0 && as_status=1
+  if test "$3"; then
+    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+  fi
+  $as_echo "$as_me: error: $1" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='GLPK'
+PACKAGE_TARNAME='glpk'
+PACKAGE_VERSION='4.47'
+PACKAGE_STRING='GLPK 4.47'
+PACKAGE_BUGREPORT='bug-glpk@gnu.org'
+PACKAGE_URL=''
+
+ac_unique_file="src/glpk.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+CPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+RANLIB
+AR
+DLLTOOL
+OBJDUMP
+to_host_path_cmd
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+GREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_gmp
+enable_dl
+enable_odbc
+enable_mysql
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+enable_libtool_lock
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)	ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information."
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures GLPK 4.47 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/glpk]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of GLPK 4.47:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-dl             enable shared library support [[default=no]]
+  --enable-odbc           enable MathProg ODBC support [[default=no]]
+  --enable-mysql          enable MathProg MySQL support [[default=no]]
+  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gmp              use GNU MP bignum library [[default=no]]
+  --with-pic              try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <bug-glpk@gnu.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+GLPK configure 4.47
+generated by GNU Autoconf 2.65
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( cat <<\_ASBOX
+## ------------------------------- ##
+## Report this to bug-glpk@gnu.org ##
+## ------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by GLPK $as_me 4.47, which was
+generated by GNU Autoconf 2.65.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+am__api_version='1.11'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  for ac_t in install-sh install.sh shtool; do
+    if test -f "$ac_dir/$ac_t"; then
+      ac_aux_dir=$ac_dir
+      ac_install_sh="$ac_aux_dir/$ac_t -c"
+      break 2
+    fi
+  done
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t "$srcdir/configure" conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$*" != "X $srcdir/configure conftest.file" \
+      && test "$*" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      as_fn_error "ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+   fi
+
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if test "${ac_cv_path_mkdir+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+  [\\/$]* | ?:[\\/]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='glpk'
+ VERSION='4.47'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+
+# Check whether --with-gmp was given.
+if test "${with_gmp+set}" = set; then :
+  withval=$with_gmp; case $withval in
+      yes | no) ;;
+      *) as_fn_error "invalid value \`$withval' for --with-gmp" "$LINENO" 5;;
+      esac
+else
+  with_gmp=no
+fi
+
+
+# Check whether --enable-dl was given.
+if test "${enable_dl+set}" = set; then :
+  enableval=$enable_dl; case $enableval in
+      yes | ltdl | dlfcn | no) ;;
+      *) as_fn_error "invalid value \`$enableval' for --enable-dl" "$LINENO" 5;;
+      esac
+else
+  enable_dl=no
+fi
+
+
+# Check whether --enable-odbc was given.
+if test "${enable_odbc+set}" = set; then :
+  enableval=$enable_odbc; case $enableval in
+      yes | unix | no) ;;
+      *) as_fn_error "invalid value \`$enableval' for --enable-odbc" "$LINENO" 5;;
+      esac
+else
+  enable_odbc=no
+fi
+
+
+# Check whether --enable-mysql was given.
+if test "${enable_mysql+set}" = set; then :
+  enableval=$enable_mysql; case $enableval in
+      yes | no) ;;
+      *) as_fn_error "invalid value \`$enableval' for --enable-mysql" "$LINENO" 5;;
+      esac
+else
+  enable_mysql=no
+fi
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "no acceptable C compiler found in \$PATH
+See \`config.log' for more details." "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "C compiler cannot create executables
+See \`config.log' for more details." "$LINENO" 5; }; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.2.7a'
+macro_revision='1.3140'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if test "${ac_cv_path_SED+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if test "${ac_cv_path_FGREP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if test "${lt_cv_path_NM+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DUMPBIN+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if test "${lt_cv_nm_interface+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build paths to $host format" >&5
+$as_echo_n "checking how to convert $build paths to $host format... " >&6; }
+if test "${lt_cv_to_host_path_cmd+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *mingw* )
+    case $build in
+      *mingw* ) # actually msys
+        lt_cv_to_host_path_cmd=func_msys_to_mingw_path_convert
+        ;;
+      *cygwin* )
+        lt_cv_to_host_path_cmd=func_cygwin_to_mingw_path_convert
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_path_cmd=func_nix_to_mingw_path_convert
+        ;;
+    esac
+    ;;
+  *cygwin* )
+    case $build in
+      *mingw* ) # actually msys
+        lt_cv_to_host_path_cmd=func_msys_to_cygwin_path_convert
+        ;;
+      *cygwin* )
+        lt_cv_to_host_path_cmd=func_noop_path_convert
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_path_cmd=func_nix_to_cygwin_path_convert
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_path_cmd=func_noop_path_convert
+    ;;
+esac
+
+fi
+
+to_host_path_cmd=$lt_cv_to_host_path_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_path_cmd" >&5
+$as_echo "$lt_cv_to_host_path_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if test "${lt_cv_ld_reload_flag+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJDUMP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if test "${lt_cv_deplibs_check_method+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DLLTOOL+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if test "${lt_cv_sharedlib_from_linklib_cmd+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AR="${ac_tool_prefix}ar"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+  ac_ct_AR=$AR
+  # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_AR="ar"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+else
+  AR="$ac_cv_prog_AR"
+fi
+
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+const struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_save_LIBS="$LIBS"
+	  lt_save_CFLAGS="$CFLAGS"
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS="$lt_save_LIBS"
+	  CFLAGS="$lt_save_CFLAGS"
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if test "${lt_cv_cc_needs_belf+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+sparc*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DSYMUTIL+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_NMEDIT+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_LIPO+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL64+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if test "${lt_cv_apple_cc_single_mod+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if test "${lt_cv_ld_exported_symbols_list+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if test "${lt_cv_ld_force_load+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[012]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+eval as_val=\$$as_ac_Header
+   if test "x$as_val" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+  enable_win32_dll=no
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; pic_mode="$withval"
+else
+  pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if test "${lt_cv_objdir+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      lt_prog_compiler_pic='-Xcompiler -fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ F* | *Sun*Fortran*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5
+$as_echo "$lt_prog_compiler_pic" >&6; }
+
+
+
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_flag_spec_ld=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec=
+	  hardcode_libdir_flag_spec_ld='-rpath $libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      export_dynamic_flag_spec='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' ${wl}-bernotok'
+	  allow_undefined_flag=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec='$convenience'
+	  fi
+	  archive_cmds_need_lc=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec=' '
+      allow_undefined_flag=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      old_archive_from_new_cmds='true'
+      # FIXME: Should let the user specify the lib program.
+      old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+      fix_srcfile_path='`cygpath -w "$srcfile"`'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    freebsd1*)
+      ld_shlibs=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_flag_spec_ld='+b $libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if test "${lt_cv_prog_compiler__b+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+        save_LDFLAGS="$LDFLAGS"
+        LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo(void) {}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+        LDFLAGS="$save_LDFLAGS"
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	  export_dynamic_flag_spec='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     hardcode_libdir_flag_spec='-R$libdir'
+	     ;;
+	   *)
+	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='${wl}-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='${wl}-z,text'
+      allow_undefined_flag='${wl}-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if test "${lt_cv_archive_cmds_need_lc+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl
+	  pic_flag=$lt_prog_compiler_pic
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag
+	  allow_undefined_flag=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc=no
+	  else
+	    lt_cv_archive_cmds_need_lc=yes
+	  fi
+	  allow_undefined_flag=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[123]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test "X$hardcode_automatic" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+   test "$inherit_rpath" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = x""yes; then :
+  lt_cv_dlopen="shl_load"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = x""yes; then :
+  lt_cv_dlopen="dlopen"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = x""yes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = x""yes; then :
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self_static+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report which library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for exp in -lm" >&5
+$as_echo_n "checking for exp in -lm... " >&6; }
+if test "${ac_cv_lib_m_exp+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char exp ();
+int
+main ()
+{
+return exp ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_exp=yes
+else
+  ac_cv_lib_m_exp=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_exp" >&5
+$as_echo "$ac_cv_lib_m_exp" >&6; }
+if test "x$ac_cv_lib_m_exp" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+
+ac_fn_c_check_header_mongrel "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_time_h" = x""yes; then :
+
+$as_echo "#define HAVE_SYS_TIME_H 1" >>confdefs.h
+
+fi
+
+
+
+ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
+if test "x$ac_cv_func_gettimeofday" = x""yes; then :
+
+$as_echo "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use GNU MP bignum library" >&5
+$as_echo_n "checking whether to use GNU MP bignum library... " >&6; }
+if test "$with_gmp" = "yes"; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_GMP 1" >>confdefs.h
+
+   LIBS="-lgmp $LIBS"
+else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable shared library support" >&5
+$as_echo_n "checking whether to enable shared library support... " >&6; }
+if test "$enable_dl" = "yes"; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ltdl" >&5
+$as_echo "ltdl" >&6; }
+
+$as_echo "#define HAVE_LTDL 1" >>confdefs.h
+
+   LIBS="-lltdl $LIBS"
+elif test "$enable_dl" = "ltdl"; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ltdl" >&5
+$as_echo "ltdl" >&6; }
+
+$as_echo "#define HAVE_LTDL 1" >>confdefs.h
+
+   LIBS="-lltdl $LIBS"
+elif test "$enable_dl" = "dlfcn"; then
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: dlfcn" >&5
+$as_echo "dlfcn" >&6; }
+
+$as_echo "#define HAVE_DLFCN 1" >>confdefs.h
+
+else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+case $host_os in
+   darwin* | macosx*)
+      LIBIODBC="libiodbc.dylib"
+      LIBODBC="libodbc.dylib"
+      LIBMYSQL="libmysqlclient.dylib"
+      ;;
+   *)
+      LIBIODBC="libiodbc.so"
+      LIBODBC="libodbc.so"
+      LIBMYSQL="libmysqlclient.so"
+      ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable MathProg ODBC support" >&5
+$as_echo_n "checking whether to enable MathProg ODBC support... " >&6; }
+if test "$enable_odbc" = "yes"; then
+   if test "$enable_dl" = "no"; then
+      as_fn_error "--enable-odbc requires --enable-dl" "$LINENO" 5
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define ODBC_DLNAME "$LIBIODBC"
+_ACEOF
+
+elif test "$enable_odbc" = "unix"; then
+   if test "$enable_dl" = "no"; then
+      as_fn_error "--enable-odbc requires --enable-dl" "$LINENO" 5
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: unix" >&5
+$as_echo "unix" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define ODBC_DLNAME "$LIBODBC"
+_ACEOF
+
+else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable MathProg MySQL support" >&5
+$as_echo_n "checking whether to enable MathProg MySQL support... " >&6; }
+if test "$enable_mysql" = "yes"; then
+   if test "$enable_dl" = "no"; then
+      as_fn_error "--enable-mysql requires --enable-dl" "$LINENO" 5
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+   CPPFLAGS="-I/usr/include/mysql $CPPFLAGS"
+
+cat >>confdefs.h <<_ACEOF
+#define MYSQL_DLNAME "$LIBMYSQL"
+_ACEOF
+
+else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ac_config_files="$ac_config_files src/Makefile examples/Makefile Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$?; test $as_status -eq 0 && as_status=1
+  if test "$3"; then
+    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+  fi
+  $as_echo "$as_me: error: $1" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in #(
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by GLPK $as_me 4.47, which was
+generated by GNU Autoconf 2.65.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-glpk@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+GLPK config.status 4.47
+configured by $0, generated by GNU Autoconf 2.65,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_path_cmd='`$ECHO "$lt_cv_to_host_path_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_wl \
+lt_prog_compiler_pic \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_flag_spec_ld \
+hardcode_libdir_separator \
+fix_srcfile_path \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+    "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+  *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+  || as_fn_error "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[	 ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_t"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin" \
+      || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+  || as_fn_error "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out" && rm -f "$tmp/out";;
+  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+    } >"$tmp/config.h" \
+      || as_fn_error "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$tmp/config.h" "$ac_file" \
+	|| as_fn_error "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named `Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running `make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build paths to \$host format.
+to_host_path_cmd=$lt_cv_to_host_path_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking.  This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  case $xsi_shell in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+  func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+  # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+  # positional parameters, so assign one to ordinary parameter first.
+  func_stripname_result=${3}
+  func_stripname_result=${func_stripname_result#"${1}"}
+  func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=${1%%=*}
+  func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  case ${1} in
+    *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+    *)    func_lo2o_result=${1} ;;
+  esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=$(( $* ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=${#1}
+}
+
+_LT_EOF
+    ;;
+  *) # Bourne compatible functions.
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  # Extract subdirectory from the argument.
+  func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+  if test "X$func_dirname_result" = "X${1}"; then
+    func_dirname_result="${3}"
+  else
+    func_dirname_result="$func_dirname_result${2}"
+  fi
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+}
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+  case ${2} in
+    .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[^=]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=`expr "$@"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$1+=\$2"
+}
+_LT_EOF
+    ;;
+  *)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$1=\$$1\$2"
+}
+
+_LT_EOF
+    ;;
+  esac
+
+
+  sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit $?
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
Index: deps/glpk/configure.ac
===================================================================
--- deps/glpk/configure.ac	(revision 9)
+++ deps/glpk/configure.ac	(revision 9)
@@ -0,0 +1,141 @@
+dnl Process this file with autoconf to produce a configure script
+
+AC_INIT([GLPK], [4.47], [bug-glpk@gnu.org])
+
+AC_CONFIG_SRCDIR([src/glpk.h])
+
+AC_CONFIG_MACRO_DIR([m4])
+
+AM_INIT_AUTOMAKE
+
+AC_CONFIG_HEADERS([config.h])
+
+AC_ARG_WITH(gmp,
+AC_HELP_STRING([--with-gmp],
+   [use GNU MP bignum library [[default=no]]]),
+   [case $withval in
+      yes | no) ;;
+      *) AC_MSG_ERROR([invalid value `$withval' for --with-gmp]);;
+      esac],
+   [with_gmp=no])
+
+AC_ARG_ENABLE(dl,
+AC_HELP_STRING([--enable-dl],
+   [enable shared library support [[default=no]]]),
+   [case $enableval in
+      yes | ltdl | dlfcn | no) ;;
+      *) AC_MSG_ERROR([invalid value `$enableval' for --enable-dl]);;
+      esac],
+   [enable_dl=no])
+
+AC_ARG_ENABLE(odbc,
+AC_HELP_STRING([--enable-odbc],
+   [enable MathProg ODBC support [[default=no]]]),
+   [case $enableval in
+      yes | unix | no) ;;
+      *) AC_MSG_ERROR([invalid value `$enableval' for --enable-odbc]);;
+      esac],
+   [enable_odbc=no])
+
+AC_ARG_ENABLE(mysql,
+AC_HELP_STRING([--enable-mysql],
+   [enable MathProg MySQL support [[default=no]]]),
+   [case $enableval in
+      yes | no) ;;
+      *) AC_MSG_ERROR([invalid value `$enableval' for --enable-mysql]);;
+      esac],
+   [enable_mysql=no])
+
+dnl Disable unnecessary libtool tests
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])
+define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])
+
+dnl Check for programs
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+dnl Check for math library
+AC_CHECK_LIB([m], [exp])
+
+dnl Check for <sys/time.h> header
+AC_CHECK_HEADER([sys/time.h],
+   AC_DEFINE([HAVE_SYS_TIME_H], [1], [N/A]))
+
+dnl Check for gettimeofday function
+AC_CHECK_FUNC([gettimeofday],
+   AC_DEFINE([HAVE_GETTIMEOFDAY], [1], [N/A]))
+
+AC_MSG_CHECKING([whether to use GNU MP bignum library])
+if test "$with_gmp" = "yes"; then
+   AC_MSG_RESULT([yes])
+   AC_DEFINE([HAVE_GMP], [1], [N/A])
+   LIBS="-lgmp $LIBS"
+else
+   AC_MSG_RESULT([no])
+fi
+
+AC_MSG_CHECKING([whether to enable shared library support])
+if test "$enable_dl" = "yes"; then
+   AC_MSG_RESULT([ltdl])
+   AC_DEFINE([HAVE_LTDL], [1], [N/A])
+   LIBS="-lltdl $LIBS"
+elif test "$enable_dl" = "ltdl"; then
+   AC_MSG_RESULT([ltdl])
+   AC_DEFINE([HAVE_LTDL], [1], [N/A])
+   LIBS="-lltdl $LIBS"
+elif test "$enable_dl" = "dlfcn"; then
+   AC_MSG_RESULT([dlfcn])
+   AC_DEFINE([HAVE_DLFCN], [1], [N/A])
+else
+   AC_MSG_RESULT([no])
+fi
+
+case $host_os in
+   darwin* | macosx*)
+      LIBIODBC="libiodbc.dylib"
+      LIBODBC="libodbc.dylib"
+      LIBMYSQL="libmysqlclient.dylib"
+      ;;
+   *)
+      LIBIODBC="libiodbc.so"
+      LIBODBC="libodbc.so"
+      LIBMYSQL="libmysqlclient.so"
+      ;;
+esac
+
+AC_MSG_CHECKING([whether to enable MathProg ODBC support])
+if test "$enable_odbc" = "yes"; then
+   if test "$enable_dl" = "no"; then
+      AC_MSG_ERROR([--enable-odbc requires --enable-dl])
+   fi
+   AC_MSG_RESULT([yes])
+   AC_DEFINE_UNQUOTED([ODBC_DLNAME], ["$LIBIODBC"], [N/A])
+elif test "$enable_odbc" = "unix"; then
+   if test "$enable_dl" = "no"; then
+      AC_MSG_ERROR([--enable-odbc requires --enable-dl])
+   fi
+   AC_MSG_RESULT([unix])
+   AC_DEFINE_UNQUOTED([ODBC_DLNAME], ["$LIBODBC"], [N/A])
+else
+   AC_MSG_RESULT([no])
+fi
+
+AC_MSG_CHECKING([whether to enable MathProg MySQL support])
+if test "$enable_mysql" = "yes"; then
+   if test "$enable_dl" = "no"; then
+      AC_MSG_ERROR([--enable-mysql requires --enable-dl])
+   fi
+   AC_MSG_RESULT([yes])
+   CPPFLAGS="-I/usr/include/mysql $CPPFLAGS"
+   AC_DEFINE_UNQUOTED([MYSQL_DLNAME], ["$LIBMYSQL"], [N/A])
+else
+   AC_MSG_RESULT([no])
+fi
+
+AC_CONFIG_FILES(
+   [src/Makefile examples/Makefile Makefile])
+AC_OUTPUT
+
+dnl eof
Index: deps/glpk/depcomp
===================================================================
--- deps/glpk/depcomp	(revision 9)
+++ deps/glpk/depcomp	(revision 9)
@@ -0,0 +1,630 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
+# Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by `PROGRAMS ARGS'.
+  object      Object file output by `PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputing dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+   # This is just like msvisualcpp but w/o cygpath translation.
+   # Just convert the backslash-escaped backslashes to single forward
+   # slashes to satisfy depend.m4
+   cygpath_u="sed s,\\\\\\\\,/,g"
+   depmode=msvisualcpp
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'.  On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like `#:fec' to the end of the
+    # dependency line.
+    tr ' ' '
+' < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr '
+' ' ' >> "$depfile"
+    echo >> "$depfile"
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' '
+' < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form `foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # `$object: dependent.h' and one to simply `dependent.h:'.
+    sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+    # That's a tab and a space in the [].
+    sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+icc)
+  # Intel's C compiler understands `-MD -MF file'.  However on
+  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # ICC 7.0 will fill foo.d with something like
+  #    foo.o: sub/foo.c
+  #    foo.o: sub/foo.h
+  # which is wrong.  We want:
+  #    sub/foo.o: sub/foo.c
+  #    sub/foo.o: sub/foo.h
+  #    sub/foo.c:
+  #    sub/foo.h:
+  # ICC 7.1 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using \ :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+    sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add `dependent.h:' lines.
+    sed -ne '2,${
+	       s/^ *//
+	       s/ \\*$//
+	       s/$/:/
+	       p
+	     }' "$tmpdepfile" >> "$depfile"
+  else
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in `foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      # With Tru64 cc, shared objects can also be used to make a
+      # static library.  This mechanism is used in libtool 1.4 series to
+      # handle both shared and static libraries in a single compilation.
+      # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+      #
+      # With libtool 1.5 this exception was removed, and libtool now
+      # generates 2 separate objects for the 2 libraries.  These two
+      # compilations output dependencies in $dir.libs/$base.o.d and
+      # in $dir$base.o.d.  We have to check for both files, because
+      # one of the two compilations can be disabled.  We should prefer
+      # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+      # automatically cleaned when .libs/ is deleted, while ignoring
+      # the former would cause a distcleancheck panic.
+      tmpdepfile1=$dir.libs/$base.lo.d   # libtool 1.4
+      tmpdepfile2=$dir$base.o.d          # libtool 1.5
+      tmpdepfile3=$dir.libs/$base.o.d    # libtool 1.5
+      tmpdepfile4=$dir.libs/$base.d      # Compaq CCC V6.2-504
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1=$dir$base.o.d
+      tmpdepfile2=$dir$base.d
+      tmpdepfile3=$dir$base.d
+      tmpdepfile4=$dir$base.d
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+      exit $stat
+   fi
+
+   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+   do
+     test -f "$tmpdepfile" && break
+   done
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      # That's a tab and a space in the [].
+      sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for `:'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  "$@" $dashmflag |
+    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+       -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+	set fnord "$@"
+	shift
+	shift
+	;;
+    *)
+	set fnord "$@" "$arg"
+	shift
+	shift
+	;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::	\1 \\:p' >> "$depfile"
+  echo "	" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
Index: deps/glpk/doc/cnfsat.tex
===================================================================
--- deps/glpk/doc/cnfsat.tex	(revision 9)
+++ deps/glpk/doc/cnfsat.tex	(revision 9)
@@ -0,0 +1,380 @@
+%* cnfsat.tex *%
+
+\documentclass[11pt,draft]{article}
+
+\begin{document}
+
+\title{CNF Satisfiability Problem}
+
+\author{Andrew Makhorin {\tt<mao@gnu.org>}}
+
+\date{August 2011}
+
+\maketitle
+
+\section{Introduction}
+
+The {\it Satisfiability Problem (SAT)} is a classic combinatorial
+problem. Given a Boolean formula of $n$ variables
+$$f(x_1,x_2,\dots,x_n),\eqno(1.1)$$
+this problem is to find such values of the variables, on which the
+formula takes on the value {\it true}.
+
+The {\it CNF Satisfiability Problem (CNF-SAT)} is a version of the
+Satisfiability Problem, where the Boolean formula (1.1) is specified
+in the {\it Conjunctive Normal Form (CNF)}, that means that it is a
+conjunction of {\it clauses}, where a clause is a disjunction of
+{\it literals}, and a literal is a variable or its negation.
+For example:
+$$(x_1\vee x_2)\;\&\;(\neg x_2\vee x_3\vee\neg x_4)\;\&\;(\neg
+x_1\vee x_4).\eqno(1.2)$$
+Here $x_1$, $x_2$, $x_3$, $x_4$ are Boolean variables to be assigned,
+$\neg$ means
+negation (logical {\it not}), $\vee$ means disjunction (logical
+{\it or}), and $\&$ means conjunction (logical {\it and}). One may
+note that the formula (1.2) is {\it satisfiable}, because on
+$x_1$ = {\it true}, $x_2$ = {\it false}, $x_3$ = {\it false}, and
+$x_4$ = {\it true} it takes on the value {\it true}. If a formula
+is not satisfiable, it is called {\it unsatisfiable}, that means that
+it takes on the value {\it false} on any values of its variables.
+
+Any CNF-SAT problem can be easily translated to a 0-1 programming
+problem as follows. A Boolean variable $x$ can be modeled by a binary
+variable in a natural way: $x=1$ means that $x$ takes on the value
+{\it true}, and $x=0$ means that $x$ takes on the value {\it false}.
+Then, if a literal is a negated variable, i.e. $t=\neg x$, it can
+be expressed as $t=1-x$. Since a formula in CNF is a conjunction of
+clauses, to provide its satisfiability we should require all its
+clauses to  take on the value {\it true}. A particular clause is
+a disjunction of literals:
+$$t\vee t'\vee t''\dots ,\eqno(1.3)$$
+so it takes on the value {\it true} iff at least one of its literals
+takes on the value {\it true}, that can be expressed as the following
+inequality constraint:
+$$t+t'+t''+\dots\geq 1.\eqno(1.4)$$
+Note that no objective function is used in this case, because only
+a feasible solution needs to be found.
+
+For example, the formula (1.2) can be translated to the following
+constraints:
+$$\begin{array}{c@{\ }c@{\ }c@{\ }c@{\ }c@{\ }c@{\ }c@{\ }c@{\ }c}
+x_1&+&x_2&&&&&\geq&1\\
+&&(1-x_2)&+&x_3&+&(1-x_4)&\geq&1\\
+(1-x_1)&&&&&+&x_4&\geq&1\\
+\end{array}$$
+$$x_1, x_2, x_3, x_4\in\{0,1\}$$
+Carrying out all constant terms to the right-hand side gives
+corresponding 0-1 programming problem in the standard format:
+$$\begin{array}{r@{\ }c@{\ }c@{\ }c@{\ }c@{\ }c@{\ }c@{\ }c@{\ }r}
+x_1&+&x_2&&&&&\geq&1\\
+&-&x_2&+&x_3&-&x_4&\geq&-1\\
+-x_1&&&&&+&x_4&\geq&0\\
+\end{array}$$
+$$x_1, x_2, x_3, x_4\in\{0,1\}$$
+
+In general case translation of a CNF-SAT problem results in the
+following 0-1 programming problem:
+$$\sum_{j\in J^+_i}x_j-\sum_{j\in J^-_i}x_j\geq 1-|J^-_i|,
+\ \ \ i=1,\dots,m\eqno(1.5)$$
+$$x_j\in\{0,1\},\ \ \ j=1,\dots,n\eqno(1.6)$$
+where $n$ is the number of variables, $m$ is the number of clauses
+(inequality constraints), $J^+_i\subseteq\{1,\dots,n\}$ is a subset
+of variables, whose literals in $i$-th clause do not have negation,
+and $J^-_i\subseteq\{1,\dots,n\}$ is a subset of variables, whose
+literals in $i$-th clause are negations of that variables. It is
+assumed that $J^+_i\cap J^-_i=\emptyset$ for all $i$.
+
+\newpage
+
+\section{GLPK API Routines}
+
+\subsection{glp\_read\_cnfsat---read CNF-SAT problem data in\\DIMACS
+format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_cnfsat(glp_prob *P, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_cnfsat| reads the CNF-SAT problem data from
+a text file in DIMACS format and automatically translates the data to
+corresponding 0-1 programming problem instance (1.5)--(1.6).
+
+The parameter \verb|P| specifies the problem object, to which the
+0-1 programming problem instance should be stored. Note that before
+reading data the current content of the problem object is completely
+erased with the routine \verb|glp_erase_prob|.
+
+The character string \verb|fname| specifies the name of a text file
+to be read in. (If the file name ends with the suffix `\verb|.gz|',
+the file is assumed to be compressed, in which case the routine
+decompresses it ``on the fly''.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\subsubsection*{DIMACS CNF-SAT problem format\footnote{This material
+is based on the paper ``Satisfiability Suggested Format'', which is
+publicly available at {\tt http://dimacs.rutgers.edu/}.}}
+
+The DIMACS input file is a plain ASCII text file. It contains lines of
+several types described below. A line is terminated with an end-of-line
+character. Fields in each line are separated by at least one blank
+space.
+
+\paragraph{Comment lines.} Comment lines give human-readable
+information about the file and are ignored by programs. Comment lines
+can appear anywhere in the file. Each comment line begins with a
+lower-case character \verb|c|.
+
+\begin{verbatim}
+   c This is a comment line
+\end{verbatim}
+
+\newpage
+
+\paragraph{Problem line.} There is one problem line per data file. The
+problem line must appear before any clause lines. It has the following
+format:
+
+\begin{verbatim}
+   p cnf VARIABLES CLAUSES
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|p| signifies that this is a problem
+line. The three character problem designator \verb|cnf| identifies the
+file as containing specification information for the CNF-SAT problem.
+The \verb|VARIABLES| field contains an integer value specifying $n$,
+the number of variables in the instance. The \verb|CLAUSES| field
+contains an integer value specifying $m$, the number of clauses in the
+instance.
+
+\paragraph{Clauses.} The clauses appear immediately after the problem
+line. The variables are assumed to be numbered from 1 up to $n$. It is
+not necessary that every variable appears in the instance. Each clause
+is represented by a sequence of numbers separated by either a space,
+tab, or new-line character. The non-negated version of a variable $j$
+is represented by $j$; the negated version is represented by $-j$. Each
+clause is terminated by the value 0. Unlike many formats that represent
+the end of a clause by a new-line character, this format allows clauses
+to be on multiple lines.
+
+\paragraph{Example.} Below here is an example of the data file in
+DIMACS format corresponding to the CNF-SAT problem (1.2).
+
+\begin{footnotesize}
+\begin{verbatim}
+c sample.cnf
+c
+c This is an example of the CNF-SAT problem data
+c in DIMACS format.
+c
+p cnf 4 3
+1 2 0
+-4 3
+-2 0
+-1 4 0
+c
+c eof
+\end{verbatim}
+\end{footnotesize}
+
+\newpage
+
+\subsection{glp\_check\_cnfsat---check for CNF-SAT problem instance}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_check_cnfsat(glp_prob *P);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_check_cnfsat| checks if the specified problem
+object \verb|P| contains a 0-1 programming problem instance in the
+format (1.5)--(1.6) and therefore encodes a CNF-SAT problem instance.
+
+\subsubsection*{Returns}
+
+If the specified problem object has the format (1.5)--(1.6), the
+routine returns zero, otherwise non-zero.
+
+\subsection{glp\_write\_cnfsat---write CNF-SAT problem data in\\DIMACS
+format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_cnfsat(glp_prob *P, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_cnfsat| automatically translates the
+specified 0-1 programming problem instance (1.5)--(1.6) to a CNF-SAT
+problem instance and writes the problem data to a text file in DIMACS
+format.
+
+The parameter \verb|P| is the problem object, which should specify
+a 0-1 programming problem instance in the format (1.5)--(1.6).
+
+The character string \verb|fname| specifies a name of the output text
+file to be written. (If the file name ends with suffix `\verb|.gz|',
+the file is assumed to be compressed, in which case the routine
+performs automatic compression on writing that file.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\newpage
+
+\subsection{glp\_minisat1---solve CNF-SAT problem instance with\\
+MiniSat solver}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_minisat1(glp_prob *P);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_minisat1| is a driver to MiniSat, a CNF-SAT
+solver developed by Niklas E\'en and Niklas S\"orensson, Chalmers
+University of Technology, Sweden.\footnote{The MiniSat software module
+is {\it not} part of GLPK, but is used with GLPK and included in the
+distribution.}
+
+It is assumed that the specified problem object \verb|P| contains
+a 0-1 programming problem instance in the format (1.5)--(1.6) and
+therefore encodes a CNF-SAT problem instance.
+
+If the problem instance has been successfully solved to the end, the
+routine \verb|glp_minisat1| returns 0. In this case the routine
+\verb|glp_mip_status| can be used to determine the solution status:
+
+\verb|GLP_OPT| means that the solver found an integer feasible
+solution and therefore the corresponding CNF-SAT instance is
+satisfiable;
+
+\verb|GLP_NOFEAS| means that no integer feasible solution exists and
+therefore the corresponding CNF-SAT instance is unsatisfiable.
+
+If an integer feasible solution was found, corresponding values of
+binary variables can be retrieved with the routine
+\verb|glp_mip_col_val|.
+
+\subsubsection*{Returns}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The MIP problem instance has been successfully solved. (This code
+does {\it not} necessarily mean that the solver has found feasible
+solution. It only means that the solution process was successful.)\\
+\verb|GLP_EDATA| & The specified problem object contains a MIP instance
+which does {\it not} have the format (1.5)--(1.6).\\
+\verb|GLP_EFAIL| & The solution process was unsuccessful because of the
+solver failure.\\
+\end{tabular}
+
+\newpage
+
+\subsection{glp\_intfeas1---solve integer feasibility problem}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_intfeas1| is a tentative implementation of
+an integer feasibility solver based on a CNF-SAT solver (currently
+it is MiniSat; see Subsection 2.4).
+
+If the parameter \verb|use_bound| is zero, the routine searches for
+{\it any} integer feasibile solution to the specified integer
+programming problem. Note that in this case the objective function is
+ignored.
+
+If the parameter \verb|use_bound| is non-zero, the routine searches for
+an integer feasible solution, which provides a value of the objective
+function not worse than \verb|obj_bound|. In other word, the parameter
+\verb|obj_bound| specifies an upper (in case of minimization) or lower
+(in case of maximization) bound to the objective function.
+
+If the specified problem has been successfully solved to the end, the
+routine \verb|glp_intfeas1| returns 0. In this case the routine
+\verb|glp_mip_status| can be used to determine the solution status:
+
+\begin{itemize}
+\item {\tt GLP\_FEAS} means that the solver found an integer feasible
+solution;
+
+\item {\tt GLP\_NOFEAS} means that the problem has no integer feasible
+solution (if {\tt use\_bound} is zero) or it has no integer feasible
+solution, which is not worse than {\tt obj\_bound} (if {\tt use\_bound}
+is non-zero).
+\end{itemize}
+
+If an integer feasible solution was found, corresponding values of
+variables (columns) can be retrieved with the routine
+\verb|glp_mip_col_val|.
+
+\subsubsection*{Usage Notes}
+
+The integer programming problem specified by the parameter \verb|P|
+should satisfy to the following requirements:
+
+\begin{enumerate}
+\item All variables (columns) should be either binary ({\tt GLP\_BV})
+or fixed at integer values ({\tt GLP\_FX}).
+
+\item All constraint and objective coefficients should be integer
+numbers in the range $[-2^{31},\ +2^{31}-1]$.
+\end{enumerate}
+
+Though there are no special requirements to the constraints,
+currently the routine \verb|glp_intfeas1| is efficient mainly for
+problems, where most constraints (rows) fall into the following three
+classes:
+
+\begin{enumerate}
+\item Covering inequalities
+$$\sum_{j}t_j\geq 1,$$
+where $t_j=x_j$ or $t_j=1-x_j$, $x_j$ is a binary variable.
+
+\item Packing inequalities
+$$\sum_{j}t_j\leq 1.$$
+
+\item Partitioning equalities (SOS1 constraints)
+$$\sum_{j}t_j=1.$$
+\end{enumerate}
+
+\subsubsection*{Returns}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The problem has been successfully solved. (This code does {\it not}
+necessarily mean that the solver has found an integer feasible solution.
+It only means that the solution process was successful.)\\
+
+\verb|GLP_EDATA| & The specified problem object does not satisfy to the
+requirements listed in Paragraph `Usage Notes'.\\
+
+\verb|GLP_ERANGE| & An integer overflow occured on translating the
+specified problem to a CNF-SAT problem.\\
+
+\verb|GLP_EFAIL| & The solution process was unsuccessful because of the
+solver failure.\\
+\end{tabular}
+
+\end{document}
Index: deps/glpk/doc/glpk.tex
===================================================================
--- deps/glpk/doc/glpk.tex	(revision 9)
+++ deps/glpk/doc/glpk.tex	(revision 9)
@@ -0,0 +1,128 @@
+%* glpk.tex *%
+
+%***********************************************************************
+%  This code is part of GLPK (GNU Linear Programming Kit).
+%
+%  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+%  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+%  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+%  E-mail: <mao@gnu.org>.
+%
+%  GLPK is free software: you can redistribute it and/or modify it
+%  under the terms of the GNU General Public License as published by
+%  the Free Software Foundation, either version 3 of the License, or
+%  (at your option) any later version.
+%
+%  GLPK is distributed in the hope that it will be useful, but WITHOUT
+%  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+%  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+%  License for more details.
+%
+%  You should have received a copy of the GNU General Public License
+%  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+%***********************************************************************
+
+\documentclass[11pt]{report}
+\usepackage{amssymb}
+\usepackage{lscape}
+\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
+urlcolor=blue]{hyperref}
+\usepackage[all]{xy}
+
+\renewcommand\contentsname{\sf\bfseries Contents}
+\renewcommand\chaptername{\sf\bfseries Chapter}
+\renewcommand\appendixname{\sf\bfseries Appendix}
+
+\begin{document}
+
+\thispagestyle{empty}
+
+\begin{center}
+
+\vspace*{1in}
+
+\begin{huge}
+\sf\bfseries GNU Linear Programming Kit
+\end{huge}
+
+\vspace{0.5in}
+
+\begin{LARGE}
+\sf Reference Manual
+\end{LARGE}
+
+\vspace{0.5in}
+
+\begin{LARGE}
+\sf for GLPK Version 4.45
+\end{LARGE}
+
+\vspace{0.5in}
+\begin{Large}
+\sf (DRAFT, December 2010)
+\end{Large}
+\end{center}
+
+\newpage
+
+\vspace*{1in}
+
+\vfill
+
+\noindent
+The GLPK package is part of the GNU Project released under the aegis of
+GNU.
+
+\medskip \noindent
+Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+
+\medskip \noindent
+Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+\medskip \noindent
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+\medskip \noindent
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of
+a permission notice identical to this one.
+
+\medskip \noindent
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+
+\tableofcontents
+
+\include{glpk01}
+
+\include{glpk02}
+
+\include{glpk03}
+
+\include{glpk04}
+
+\include{glpk05}
+
+\include{glpk06}
+
+\appendix
+
+\include{glpk07}
+
+\include{glpk08}
+
+\include{glpk09}
+
+\include{glpk10}
+
+\include{glpk11}
+
+\include{glpk12}
+
+\end{document}
Index: deps/glpk/doc/glpk01.tex
===================================================================
--- deps/glpk/doc/glpk01.tex	(revision 9)
+++ deps/glpk/doc/glpk01.tex	(revision 9)
@@ -0,0 +1,348 @@
+%* glpk01.tex *%
+
+\chapter{Introduction}
+
+GLPK (\underline{G}NU \underline{L}inear \underline{P}rogramming
+\underline{K}it) is a set of routines written in the ANSI C programming
+language and organized in the form of a callable library. It is intended
+for solving linear programming (LP), mixed integer programming (MIP),
+and other related problems.
+
+\section{LP problem}
+\label{seclp}
+
+GLPK assumes the following formulation of {\it linear programming (LP)}
+problem:
+
+\medskip
+
+\noindent
+\hspace{.5in} minimize (or maximize)
+$$z = c_1x_{m+1} + c_2x_{m+2} + \dots + c_nx_{m+n} + c_0 \eqno (1.1)$$
+\hspace{.5in} subject to linear constraints
+$$
+\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
+x_1&=&a_{11}x_{m+1}&+&a_{12}x_{m+2}&+ \dots +&a_{1n}x_{m+n} \\
+x_2&=&a_{21}x_{m+1}&+&a_{22}x_{m+2}&+ \dots +&a_{2n}x_{m+n} \\
+\multicolumn{7}{c}
+{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
+x_m&=&a_{m1}x_{m+1}&+&a_{m2}x_{m+2}&+ \dots +&a_{mn}x_{m+n} \\
+\end{array} \eqno (1.2)
+$$
+\hspace{.5in} and bounds of variables
+$$
+\begin{array}{r@{\:}c@{\:}c@{\:}c@{\:}l}
+l_1&\leq&x_1&\leq&u_1 \\
+l_2&\leq&x_2&\leq&u_2 \\
+\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .}\\
+l_{m+n}&\leq&x_{m+n}&\leq&u_{m+n} \\
+\end{array} \eqno (1.3)
+$$
+where: $x_1, x_2, \dots, x_m$ are auxiliary variables;
+$x_{m+1}, x_{m+2}, \dots, x_{m+n}$ are\linebreak structural variables;
+$z$ is the objective function;
+$c_1, c_2, \dots, c_n$ are objective coefficients;
+$c_0$ is the constant term (``shift'') of the objective function;
+$a_{11}, a_{12}, \dots, a_{mn}$ are constraint coefficients;
+$l_1, l_2, \dots, l_{m+n}$ are lower bounds of variables;
+$u_1, u_2, \dots, u_{m+n}$ are upper bounds of variables.
+
+Auxiliary variables are also called {\it rows}, because they correspond
+to rows of the constraint matrix (i.e. a matrix built of the constraint
+coefficients). Similarly, structural variables are also called
+{\it columns}, because they correspond to columns of the constraint
+matrix.
+
+Bounds of variables can be finite as well as infinite. Besides, lower
+and upper bounds can be equal to each other. Thus, the following types
+of variables are possible:
+\begin{center}
+\begin{tabular}{r@{}c@{}ll}
+\multicolumn{3}{c}{Bounds of variable} & Type of variable \\
+\hline
+$-\infty <$ &$\ x_k\ $& $< +\infty$ & Free (unbounded) variable \\
+$l_k \leq$ &$\ x_k\ $& $< +\infty$  & Variable with lower bound \\
+$-\infty <$ &$\ x_k\ $& $\leq u_k$  & Variable with upper bound \\
+$l_k \leq$ &$\ x_k\ $& $\leq u_k$   & Double-bounded variable \\
+$l_k =$ &$\ x_k\ $& $= u_k$         & Fixed variable \\
+\end{tabular}
+\end{center}
+\noindent
+Note that the types of variables shown above are applicable to
+structural as well as to auxiliary variables.
+
+To solve the LP problem (1.1)---(1.3) is to find such values of all
+structural and auxiliary variables, which:
+
+$\bullet$ satisfy to all the linear constraints (1.2), and
+
+$\bullet$ are within their bounds (1.3), and
+
+$\bullet$ provide the smallest (in case of minimization) or the largest
+(in case of maximization) value of the objective function (1.1).
+
+\section{MIP problem}
+
+{\it Mixed integer linear programming (MIP)} problem is LP problem in
+which some variables are additionally required to be integer.
+
+GLPK assumes that MIP problem has the same formulation as ordinary
+(pure) LP problem (1.1)---(1.3), i.e. includes auxiliary and structural
+variables, which may have lower and/or upper bounds. However, in case of
+MIP problem some variables may be required to be integer. This
+additional constraint means that a value of each {\it integer variable}
+must be only integer number. (Should note that GLPK allows only
+structural variables to be of integer kind.)
+
+\section{Using the package}
+
+\subsection{Brief example}
+
+In order to understand what GLPK is from the user's standpoint,
+consider the following simple LP problem:
+
+\medskip
+
+\noindent
+\hspace{.5in} maximize
+$$z = 10 x_1 + 6 x_2 + 4 x_3$$
+\hspace{.5in} subject to
+$$
+\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
+x_1 &+&x_2 &+&x_3 &\leq 100 \\
+10 x_1 &+& 4 x_2 & +&5 x_3 & \leq 600 \\
+2 x_1 &+& 2 x_2 & +& 6 x_3 & \leq 300 \\
+\end{array}
+$$
+\hspace{.5in} where all variables are non-negative
+$$x_1 \geq 0, \ x_2 \geq 0, \ x_3 \geq 0$$
+
+At first this LP problem should be transformed to the standard form
+(1.1)---(1.3). This can be easily done by introducing auxiliary
+variables, by one for each original inequality constraint. Thus, the
+problem can be reformulated as follows:
+
+\medskip
+
+\noindent
+\hspace{.5in} maximize
+$$z = 10 x_1 + 6 x_2 + 4 x_3$$
+\hspace{.5in} subject to
+$$
+\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
+p& = &x_1 &+&x_2 &+&x_3 \\
+q& = &10 x_1 &+& 4 x_2 &+& 5 x_3 \\
+r& = &2  x_1 &+& 2 x_2 &+& 6 x_3 \\
+\end{array}
+$$
+\hspace{.5in} and bounds of variables
+$$
+\begin{array}{ccc}
+\nonumber -\infty < p \leq 100 && 0 \leq x_1 < +\infty \\
+\nonumber -\infty < q \leq 600 && 0 \leq x_2 < +\infty \\
+\nonumber -\infty < r \leq 300 && 0 \leq x_3 < +\infty \\
+\end{array}
+$$
+where $p, q, r$ are auxiliary variables (rows), and $x_1, x_2, x_3$ are
+structural variables (columns).
+
+The example C program shown below uses GLPK API routines in order to
+solve this LP problem.\footnote{If you just need to solve LP or MIP
+instance, you may write it in MPS or CPLEX LP format and then use the
+GLPK stand-alone solver to obtain a solution. This is much less
+time-consuming than programming in C with GLPK API routines.}
+
+\newpage
+
+\begin{verbatim}
+/* sample.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *lp;
+      int ia[1+1000], ja[1+1000];
+      double ar[1+1000], z, x1, x2, x3;
+s1:   lp = glp_create_prob();
+s2:   glp_set_prob_name(lp, "sample");
+s3:   glp_set_obj_dir(lp, GLP_MAX);
+s4:   glp_add_rows(lp, 3);
+s5:   glp_set_row_name(lp, 1, "p");
+s6:   glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 100.0);
+s7:   glp_set_row_name(lp, 2, "q");
+s8:   glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 600.0);
+s9:   glp_set_row_name(lp, 3, "r");
+s10:  glp_set_row_bnds(lp, 3, GLP_UP, 0.0, 300.0);
+s11:  glp_add_cols(lp, 3);
+s12:  glp_set_col_name(lp, 1, "x1");
+s13:  glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
+s14:  glp_set_obj_coef(lp, 1, 10.0);
+s15:  glp_set_col_name(lp, 2, "x2");
+s16:  glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
+s17:  glp_set_obj_coef(lp, 2, 6.0);
+s18:  glp_set_col_name(lp, 3, "x3");
+s19:  glp_set_col_bnds(lp, 3, GLP_LO, 0.0, 0.0);
+s20:  glp_set_obj_coef(lp, 3, 4.0);
+s21:  ia[1] = 1, ja[1] = 1, ar[1] =  1.0; /* a[1,1] =  1 */
+s22:  ia[2] = 1, ja[2] = 2, ar[2] =  1.0; /* a[1,2] =  1 */
+s23:  ia[3] = 1, ja[3] = 3, ar[3] =  1.0; /* a[1,3] =  1 */
+s24:  ia[4] = 2, ja[4] = 1, ar[4] = 10.0; /* a[2,1] = 10 */
+s25:  ia[5] = 3, ja[5] = 1, ar[5] =  2.0; /* a[3,1] =  2 */
+s26:  ia[6] = 2, ja[6] = 2, ar[6] =  4.0; /* a[2,2] =  4 */
+s27:  ia[7] = 3, ja[7] = 2, ar[7] =  2.0; /* a[3,2] =  2 */
+s28:  ia[8] = 2, ja[8] = 3, ar[8] =  5.0; /* a[2,3] =  5 */
+s29:  ia[9] = 3, ja[9] = 3, ar[9] =  6.0; /* a[3,3] =  6 */
+s30:  glp_load_matrix(lp, 9, ia, ja, ar);
+s31:  glp_simplex(lp, NULL);
+s32:  z = glp_get_obj_val(lp);
+s33:  x1 = glp_get_col_prim(lp, 1);
+s34:  x2 = glp_get_col_prim(lp, 2);
+s35:  x3 = glp_get_col_prim(lp, 3);
+s36:  printf("\nz = %g; x1 = %g; x2 = %g; x3 = %g\n",
+         z, x1, x2, x3);
+s37:  glp_delete_prob(lp);
+      return 0;
+}
+
+/* eof */
+\end{verbatim}
+
+The statement \verb|s1| creates a problem object. Being created the
+object is initially empty. The statement \verb|s2| assigns a symbolic
+name to the problem object.
+
+The statement \verb|s3| calls the routine \verb|glp_set_obj_dir| in
+order to set the optimization direction flag, where \verb|GLP_MAX| means
+maximization.
+
+The statement \verb|s4| adds three rows to the problem object.
+
+The statement \verb|s5| assigns the symbolic name `\verb|p|' to the
+first row, and the statement \verb|s6| sets the type and bounds of the
+first row, where \verb|GLP_UP| means that the row has an upper bound.
+The statements \verb|s7|, \verb|s8|, \verb|s9|, \verb|s10| are used in
+the same way in order to assign the symbolic names `\verb|q|' and
+`\verb|r|' to the second and third rows and set their types and bounds.
+
+The statement \verb|s11| adds three columns to the problem object.
+
+The statement \verb|s12| assigns the symbolic name `\verb|x1|' to the
+first column, the statement \verb|s13| sets the type and bounds of the
+first column, where \verb|GLP_LO| means that the column has an lower
+bound, and the statement \verb|s14| sets the objective coefficient for
+the first column. The statements \verb|s15|---\verb|s20| are used in the
+same way in order to assign the symbolic names `\verb|x2|' and
+`\verb|x3|' to the second and third columns and set their types, bounds,
+and objective coefficients.
+
+The statements \verb|s21|---\verb|s29| prepare non-zero elements of the
+constraint matrix (i.e. constraint coefficients). Row indices of each
+element are stored in the array \verb|ia|, column indices are stored in
+the array \verb|ja|, and numerical values of corresponding elements are
+stored in the array \verb|ar|. Then the statement \verb|s30| calls
+the routine \verb|glp_load_matrix|, which loads information from these
+three arrays into the problem object.
+
+Now all data have been entered into the problem object, and therefore
+the statement \verb|s31| calls the routine \verb|glp_simplex|, which is
+a driver to the simplex method, in order to solve the LP problem. This
+routine finds an optimal solution and stores all relevant information
+back into the problem object.
+
+The statement \verb|s32| obtains a computed value of the objective
+function, and the statements \verb|s33|---\verb|s35| obtain computed
+values of structural variables (columns), which correspond to the
+optimal basic solution found by the solver.
+
+The statement \verb|s36| writes the optimal solution to the standard
+output. The printout may look like follows:
+
+{\footnotesize
+\begin{verbatim}
+*     0:   objval =   0.000000000e+00   infeas =   0.000000000e+00 (0)
+*     2:   objval =   7.333333333e+02   infeas =   0.000000000e+00 (0)
+OPTIMAL SOLUTION FOUND
+
+z = 733.333; x1 = 33.3333; x2 = 66.6667; x3 = 0
+\end{verbatim}
+
+}
+
+Finally, the statement \verb|s37| calls the routine
+\verb|glp_delete_prob|, which frees all the memory allocated to the
+problem object.
+
+\subsection{Compiling}
+
+The GLPK package has the only header file \verb|glpk.h|, which should
+be available on compiling a C (or C++) program using GLPK API routines.
+
+If the header file is installed in the default location
+\verb|/usr/local/include|, the following typical command may be used to
+compile, say, the example C program described above with the GNU C
+compiler:
+
+\begin{verbatim}
+   $ gcc -c sample.c
+\end{verbatim}
+
+If \verb|glpk.h| is not in the default location, the corresponding
+directory containing it should be made known to the C compiler through
+\verb|-I| option, for example:
+
+\begin{verbatim}
+   $ gcc -I/foo/bar/glpk-4.15/include -c sample.c
+\end{verbatim}
+
+In any case the compilation results in an object file \verb|sample.o|.
+
+\subsection{Linking}
+
+The GLPK library is a single file \verb|libglpk.a|. (On systems which
+support shared libraries there may be also a shared version of the
+library \verb|libglpk.so|.)
+
+If the library is installed in the default
+location \verb|/usr/local/lib|, the following typical command may be
+used to link, say, the example C program described above against with
+the library:
+
+\begin{verbatim}
+   $ gcc sample.o -lglpk -lm
+\end{verbatim}
+
+If the GLPK library is not in the default location, the corresponding
+directory containing it should be made known to the linker through
+\verb|-L| option, for example:
+
+\begin{verbatim}
+   $ gcc -L/foo/bar/glpk-4.15 sample.o -lglpk -lm
+\end{verbatim}
+
+Depending on configuration of the package linking against with the GLPK
+library may require the following optional libraries:
+
+\bigskip
+
+\begin{tabular}{@{}ll}
+\verb|-lgmp|  & the GNU MP bignum library; \\
+\verb|-lz|    & the zlib data compression library; \\
+\verb|-lltdl| & the GNU ltdl shared support library. \\
+\end{tabular}
+
+\bigskip
+
+\noindent
+in which case corresponding libraries should be also made known to the
+linker, for example:
+
+\begin{verbatim}
+   $ gcc sample.o -lglpk -lz -lltdl -lm
+\end{verbatim}
+
+For more details about configuration options of the GLPK package see
+Appendix \ref{install}, page \pageref{install}.
+
+%* eof *%
Index: deps/glpk/doc/glpk02.tex
===================================================================
--- deps/glpk/doc/glpk02.tex	(revision 9)
+++ deps/glpk/doc/glpk02.tex	(revision 9)
@@ -0,0 +1,3406 @@
+%* glpk02.tex *%
+
+\chapter{Basic API Routines}
+
+This chapter describes GLPK API routines intended for using in
+application programs.
+
+\subsubsection*{Library header}
+
+All GLPK API data types and routines are defined in the header file
+\verb|glpk.h|. It should be included in all source files which use
+GLPK API, either directly or indirectly through some other header file
+as follows:
+
+\begin{verbatim}
+   #include <glpk.h>
+\end{verbatim}
+
+\subsubsection*{Error handling}
+
+If some GLPK API routine detects erroneous or incorrect data passed by
+the application program, it writes appropriate diagnostic messages to
+the terminal and then abnormally terminates the application program.
+In most practical cases this allows to simplify programming by avoiding
+numerous checks of return codes. Thus, in order to prevent crashing the
+application program should check all data, which are suspected to be
+incorrect, before calling GLPK API routines.
+
+Should note that this kind of error handling is used only in cases of
+incorrect data passed by the application program. If, for example, the
+application program calls some GLPK API routine to read data from an
+input file and these data are incorrect, the GLPK API routine reports
+about error in the usual way by means of the return code.
+
+\subsubsection*{Thread safety}
+
+Currently GLPK API routines are non-reentrant and therefore cannot be
+used in multi-threaded programs.
+
+\subsubsection*{Array indexing}
+
+Normally all GLPK API routines start array indexing from 1, not from 0
+(except the specially stipulated cases). This means, for example, that
+if some vector $x$ of the length $n$ is passed as an array to some GLPK
+API routine, the latter expects vector components to be placed in
+locations \verb|x[1]|, \verb|x[2]|, \dots, \verb|x[n]|, and the location
+\verb|x[0]| normally is not used.
+
+In order to avoid indexing errors it is most convenient and most
+reliable to declare the array \verb|x| as follows:
+
+\begin{verbatim}
+   double x[1+n];
+\end{verbatim}
+
+\noindent
+or to allocate it as follows:
+
+\begin{verbatim}
+   double *x;
+   . . .
+   x = calloc(1+n, sizeof(double));
+\end{verbatim}
+
+\noindent
+In both cases one extra location \verb|x[0]| is reserved that allows
+passing the array to GLPK routines in a usual way.
+
+\section{Problem object}
+
+All GLPK API routines deal with so called {\it problem object}, which
+is a program object of type \verb|glp_prob| and intended to represent
+a particular LP or MIP instance.
+
+The type \verb|glp_prob| is a data structure declared in the header
+file \verb|glpk.h| as follows:
+
+\begin{verbatim}
+   typedef struct { ... } glp_prob;
+\end{verbatim}
+
+Problem objects (i.e. program objects of the \verb|glp_prob| type) are
+allocated and managed internally by the GLPK API routines. The
+application program should never use any members of the \verb|glp_prob|
+structure directly and should deal only with pointers to these objects
+(that is, \verb|glp_prob *| values).
+
+\pagebreak
+
+The problem object consists of five segments, which are:
+
+$\bullet$ problem segment,
+
+$\bullet$ basis segment,
+
+$\bullet$ interior point segment,
+
+$\bullet$ MIP segment, and
+
+$\bullet$ control parameters and statistics segment.
+
+\subsubsection*{Problem segment}
+
+The {\it problem segment} contains original LP/MIP data, which
+corresponds to the problem formulation (1.1)---(1.3) (see Section
+\ref{seclp}, page \pageref{seclp}). It includes the following
+components:
+
+$\bullet$ rows (auxiliary variables),
+
+$\bullet$ columns (structural variables),
+
+$\bullet$ objective function, and
+
+$\bullet$ constraint matrix.
+
+Rows and columns have the same set of the following attributes:
+
+$\bullet$ ordinal number,
+
+$\bullet$ symbolic name (1 up to 255 arbitrary graphic characters),
+
+$\bullet$ type (free, lower bound, upper bound, double bound, fixed),
+
+$\bullet$ numerical values of lower and upper bounds,
+
+$\bullet$ scale factor.
+
+{\it Ordinal numbers} are intended for referencing rows and columns.
+Row ordinal numbers are integers $1, 2, \dots, m$, and column ordinal
+numbers are integers $1, 2, \dots, n$, where $m$ and $n$ are,
+respectively, the current number of rows and columns in the problem
+object.
+
+{\it Symbolic names} are intended for informational purposes. They also
+can be used for referencing rows and columns.
+
+{\it Types and bounds} of rows (auxiliary variables) and columns
+(structural variables) are explained above (see Section \ref{seclp},
+page \pageref{seclp}).
+
+{\it Scale factors} are used internally for scaling rows and columns of
+the constraint matrix.
+
+Information about the {\it objective function} includes numerical
+values of objective coefficients and a flag, which defines the
+optimization direction (i.e. minimization or maximization).
+
+The {\it constraint matrix} is a $m \times n$ rectangular matrix built
+of constraint coefficients $a_{ij}$, which defines the system of linear
+constraints (1.2) (see Section \ref{seclp}, page \pageref{seclp}). This
+matrix is stored in the problem object in both row-wise and column-wise
+sparse formats.
+
+Once the problem object has been created, the application program can
+access and modify any components of the problem segment in arbitrary
+order.
+
+\subsubsection*{Basis segment}
+
+The {\it basis segment} of the problem object keeps information related
+to the current basic solution. It includes:
+
+$\bullet$ row and column statuses,
+
+$\bullet$ basic solution statuses,
+
+$\bullet$ factorization of the current basis matrix, and
+
+$\bullet$ basic solution components.
+
+The {\it row and column statuses} define which rows and columns are
+basic and which are non-basic. These statuses may be assigned either by
+the application program of by some API routines. Note that these
+statuses are always defined independently on whether the corresponding
+basis is valid or not.
+
+The {\it basic solution statuses} include the {\it primal status} and
+the {\it dual status}, which are set by the simplex-based solver once
+the problem has been solved. The primal status shows whether a primal
+basic solution is feasible, infeasible, or undefined. The dual status
+shows the same for a dual basic solution.
+
+The {\it factorization of the basis matrix} is some factorized form
+(like LU-factorization) of the current basis matrix (defined by the
+current row and column statuses). The factorization is used by the
+simplex-based solver and kept when the solver terminates the search.
+This feature allows efficiently reoptimizing the problem after some
+modifications (for example, after changing some bounds or objective
+coefficients). It also allows performing the post-optimal analysis (for
+example, computing components of the simplex table, etc.).
+
+The {\it basic solution components} include primal and dual values of
+all auxiliary and structural variables for the most recently obtained
+basic solution.
+
+\subsubsection*{Interior point segment}
+
+The {\it interior point segment} is automatically allocated after the
+problem has been solved using the interior point solver. It contains
+interior point solution components, which include the solution status,
+and primal and dual values of all auxiliary and structural variables.
+
+\subsubsection*{MIP segment}
+
+The {\it MIP segment} is used only for MIP problems. This segment
+includes:
+
+$\bullet$ column kinds,
+
+$\bullet$ MIP solution status, and
+
+$\bullet$ MIP solution components.
+
+The {\it column kinds} define which columns (i.e. structural variables)
+are integer and which are continuous.
+
+The {\it MIP solution status} is set by the MIP solver and shows whether
+a MIP solution is integer optimal, integer feasible (non-optimal), or
+undefined.
+
+The {\it MIP solution components} are computed by the MIP solver and
+include primal values of all auxiliary and structural variables for the
+most recently obtained MIP solution.
+
+Note that in case of MIP problem the basis segment corresponds to
+the optimal solution of LP relaxation, which is also available to the
+application program.
+
+Currently the search tree is not kept in the MIP segment. Therefore if
+the search has been terminated, it cannot be continued.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Problem creating and modifying routines}
+
+\subsection{glp\_create\_prob---create problem object}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+glp_prob *glp_create_prob(void);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_create_prob| creates a new problem object, which
+initially is ``empty'', i.e. has no rows and columns.
+
+\subsubsection*{Returns}
+
+The routine returns a pointer to the created object, which should be
+used in any subsequent operations on this object.
+
+\subsection{glp\_set\_prob\_name---assign (change) problem name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_prob_name(glp_prob *lp, const char *name);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_prob_name| assigns a given symbolic
+\verb|name| (1 up to 255 characters) to the specified problem object.
+
+If the parameter \verb|name| is \verb|NULL| or empty string, the routine
+erases an existing symbolic name of the problem object.
+
+\subsection{glp\_set\_obj\_name---assign (change) objective function
+name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_obj_name(glp_prob *lp, const char *name);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_obj_name| assigns a given symbolic
+\verb|name| (1 up to 255 characters) to the objective function of the
+specified problem object.
+
+If the parameter \verb|name| is \verb|NULL| or empty string, the routine
+erases an existing symbolic name of the objective function.
+
+\subsection{glp\_set\_obj\_dir---set (change) optimization direction\\
+flag}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_obj_dir(glp_prob *lp, int dir);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_obj_dir| sets (changes) the optimization
+direction flag (i.e. ``sense'' of the objective function) as specified
+by the parameter \verb|dir|:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_MIN| & minimization; \\
+\verb|GLP_MAX| & maximization. \\
+\end{tabular}
+
+\noindent
+(Note that by default the problem is minimization.)
+
+\subsection{glp\_add\_rows---add new rows to problem object}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_add_rows(glp_prob *lp, int nrs);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_add_rows| adds \verb|nrs| rows (constraints) to
+the specified problem object. New rows are always added to the end of
+the row list, so the ordinal numbers of existing rows are not changed.
+
+Being added each new row is initially free (unbounded) and has empty
+list of the constraint coefficients.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_add_rows| returns the ordinal number of the first
+new row added to the problem object.
+
+\newpage
+
+\subsection{glp\_add\_cols---add new columns to problem object}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_add_cols(glp_prob *lp, int ncs);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_add_cols| adds \verb|ncs| columns (structural
+variables) to the specified problem object. New columns are always added
+to the end of the column list, so the ordinal numbers of existing
+columns are not changed.
+
+Being added each new column is initially fixed at zero and has empty
+list of the constraint coefficients.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_add_cols| returns the ordinal number of the first
+new column added to the problem object.
+
+\subsection{glp\_set\_row\_name---assign (change) row name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_row_name(glp_prob *lp, int i, const char *name);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_row_name| assigns a given symbolic
+\verb|name| (1 up to 255 characters) to \verb|i|-th row (auxiliary
+variable) of the specified problem object.
+
+If the parameter \verb|name| is \verb|NULL| or empty string, the routine
+erases an existing name of $i$-th row.
+
+\subsection{glp\_set\_col\_name---assign (change) column name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_col_name(glp_prob *lp, int j, const char *name);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_col_name| assigns a given symbolic
+\verb|name| (1 up to 255 characters) to \verb|j|-th column (structural
+variable) of the specified problem object.
+
+If the parameter \verb|name| is \verb|NULL| or empty string, the routine
+erases an existing name of $j$-th column.
+
+\subsection{glp\_set\_row\_bnds---set (change) row bounds}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_row_bnds(glp_prob *lp, int i, int type,
+      double lb, double ub);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_row_bnds| sets (changes) the type and bounds
+of \verb|i|-th row (auxiliary variable) of the specified problem object.
+
+The parameters \verb|type|, \verb|lb|, and \verb|ub| specify the type,
+lower bound, and upper bound, respectively, as follows:
+
+\begin{center}
+\begin{tabular}{cr@{}c@{}ll}
+Type & \multicolumn{3}{c}{Bounds} & Comment \\
+\hline
+\verb|GLP_FR| & $-\infty <$ &$\ x\ $& $< +\infty$
+   & Free (unbounded) variable \\
+\verb|GLP_LO| & $lb \leq$ &$\ x\ $& $< +\infty$
+   & Variable with lower bound \\
+\verb|GLP_UP| & $-\infty <$ &$\ x\ $& $\leq ub$
+   & Variable with upper bound \\
+\verb|GLP_DB| & $lb \leq$ &$\ x\ $& $\leq ub$
+   & Double-bounded variable \\
+\verb|GLP_FX| & $lb =$ &$\ x\ $& $= ub$
+   & Fixed variable \\
+\end{tabular}
+\end{center}
+
+\noindent
+where $x$ is the auxiliary variable associated with $i$-th row.
+
+If the row has no lower bound, the parameter \verb|lb| is ignored. If
+the row has no upper bound, the parameter \verb|ub| is ignored. If the
+row is an equality constraint (i.e. the corresponding auxiliary variable
+is of fixed type), only the parameter \verb|lb| is used while the
+parameter \verb|ub| is ignored.
+
+Being added to the problem object each row is initially free, i.e. its
+type is \verb|GLP_FR|.
+
+\newpage
+
+\subsection{glp\_set\_col\_bnds---set (change) column bounds}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_col_bnds(glp_prob *lp, int j, int type,
+      double lb, double ub);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_col_bnds| sets (changes) the type and bounds
+of \verb|j|-th column (structural variable) of the specified problem
+object.
+
+The parameters \verb|type|, \verb|lb|, and \verb|ub| specify the type,
+lower bound, and upper bound, respectively, as follows:
+
+\begin{center}
+\begin{tabular}{cr@{}c@{}ll}
+Type & \multicolumn{3}{c}{Bounds} & Comment \\
+\hline
+\verb|GLP_FR| & $-\infty <$ &$\ x\ $& $< +\infty$
+   & Free (unbounded) variable \\
+\verb|GLP_LO| & $lb \leq$ &$\ x\ $& $< +\infty$
+   & Variable with lower bound \\
+\verb|GLP_UP| & $-\infty <$ &$\ x\ $& $\leq ub$
+   & Variable with upper bound \\
+\verb|GLP_DB| & $lb \leq$ &$\ x\ $& $\leq ub$
+   & Double-bounded variable \\
+\verb|GLP_FX| & $lb =$ &$\ x\ $& $= ub$
+   & Fixed variable \\
+\end{tabular}
+\end{center}
+
+\noindent
+where $x$ is the structural variable associated with $j$-th column.
+
+If the column has no lower bound, the parameter \verb|lb| is ignored.
+If the column has no upper bound, the parameter \verb|ub| is ignored.
+If the column is of fixed type, only the parameter \verb|lb| is used
+while the parameter \verb|ub| is ignored.
+
+Being added to the problem object each column is initially fixed at
+zero, i.e. its type is \verb|GLP_FX| and both bounds are 0.
+
+\subsection{glp\_set\_obj\_coef---set (change) objective coefficient
+or constant term}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_obj_coef(glp_prob *lp, int j, double coef);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_obj_coef| sets (changes) the objective
+coefficient at \verb|j|-th column (structural variable). A new value of
+the objective coefficient is specified by the parameter \verb|coef|.
+
+If the parameter \verb|j| is 0, the routine sets (changes) the constant
+term (``shift'') of the objective function.
+
+\subsection{glp\_set\_mat\_row---set (replace) row of the constraint
+matrix}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_mat_row(glp_prob *lp, int i, int len,
+      const int ind[], const double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_mat_row| stores (replaces) the contents of
+\verb|i|-th row of the constraint matrix of the specified problem
+object.
+
+Column indices and numerical values of new row elements must be placed
+in locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
+\dots, \verb|val[len]|, respectively, where $0 \leq$ \verb|len| $\leq n$
+is the new length of $i$-th row, $n$ is the current number of columns in
+the problem object. Elements with identical column indices are not
+allowed. Zero elements are allowed, but they are not stored in the
+constraint matrix.
+
+If the parameter \verb|len| is 0, the parameters \verb|ind| and/or
+\verb|val| can be specified as \verb|NULL|.
+
+\subsection{glp\_set\_mat\_col---set (replace) column of the
+constr\-aint matrix}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_mat_col(glp_prob *lp, int j, int len,
+      const int ind[], const double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_mat_col| stores (replaces) the contents of
+\verb|j|-th column of the constraint matrix of the specified problem
+object.
+
+Row indices and numerical values of new column elements must be placed
+in locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
+\dots, \verb|val[len]|, respectively, where $0 \leq$ \verb|len| $\leq m$
+is the new length of $j$-th column, $m$ is the current number of rows in
+the problem object. Elements with identical row indices are not allowed.
+Zero elements are allowed, but they are not stored in the constraint
+matrix.
+
+If the parameter \verb|len| is 0, the parameters \verb|ind| and/or
+\verb|val| can be specified as \verb|NULL|.
+
+\subsection{glp\_load\_matrix---load (replace) the whole constraint
+matrix}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
+      const int ja[], const double ar[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_load_matrix| loads the constraint matrix passed
+in  the arrays \verb|ia|, \verb|ja|, and \verb|ar| into the specified
+problem object. Before loading the current contents of the constraint
+matrix is destroyed.
+
+Constraint coefficients (elements of the constraint matrix) must be
+specified as triplets (\verb|ia[k]|, \verb|ja[k]|, \verb|ar[k]|) for
+$k=1,\dots,ne$, where \verb|ia[k]| is the row index, \verb|ja[k]| is
+the column index, and \verb|ar[k]| is a numeric value of corresponding
+constraint coefficient. The parameter \verb|ne| specifies the total
+number of (non-zero) elements in the matrix to be loaded. Coefficients
+with identical indices are not allowed. Zero coefficients are allowed,
+however, they are not stored in the constraint matrix.
+
+If the parameter \verb|ne| is 0, the parameters \verb|ia|, \verb|ja|,
+and/or \verb|ar| can be specified as \verb|NULL|.
+
+\subsection{glp\_check\_dup---check for duplicate elements in sparse
+matrix}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_check_dup(int m, int n, int ne, const int ia[],
+   const int ja[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_check_dup checks| for duplicate elements (that
+is, elements with identical indices) in a sparse matrix specified in
+the coordinate format.
+
+The parameters $m$ and $n$ specifies, respectively, the number of rows
+and columns in the matrix, $m\geq 0$, $n\geq 0$.
+
+The parameter {\it ne} specifies the number of (structurally) non-zero
+elements in the matrix, {\it ne} $\geq 0$.
+
+Elements of the matrix are specified as doublets $(ia[k],ja[k])$ for
+$k=1,\dots,ne$, where $ia[k]$ is a row index, $ja[k]$ is a column index.
+
+The routine \verb|glp_check_dup| can be used prior to a call to the
+routine \verb|glp_load_matrix| to check that the constraint matrix to
+be loaded has no duplicate elements.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_check_dup| returns one of the following values:
+
+\noindent
+\begin{tabular}{@{}r@{\ }c@{\ }l@{}}
+0&---&the matrix has no duplicate elements;\\
+$-k$&---&indices $ia[k]$ or/and $ja[k]$ are out of range;\\
+$+k$&---&element $(ia[k],ja[k])$ is duplicate.\\
+\end{tabular}
+
+\subsection{glp\_sort\_matrix---sort elements of the constraint matrix}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_sort_matrix(glp_prob *P);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sort_matrix| sorts elements of the constraint
+matrix rebuilding its row and column linked lists. On exit from the
+routine the constraint matrix is not changed, however, elements in the
+row linked lists become ordered by ascending column indices, and the
+elements in the column linked lists become ordered by ascending row
+indices.
+
+\subsection{glp\_del\_rows---delete rows from problem object}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_del_rows| deletes rows from the specified problem
+ob-\linebreak ject. Ordinal numbers of rows to be deleted should be
+placed in locations \verb|num[1]|, \dots, \verb|num[nrs]|, where
+${\tt nrs}>0$.
+
+Note that deleting rows involves changing ordinal numbers of other
+rows remaining in the problem object. New ordinal numbers of the
+remaining rows are assigned under the assumption that the original
+order of rows is not changed. Let, for example, before deletion there
+be five rows $a$, $b$, $c$, $d$, $e$ with ordinal numbers 1, 2, 3, 4, 5,
+and let rows $b$ and $d$ have been deleted. Then after deletion the
+remaining rows $a$, $c$, $e$ are assigned new oridinal numbers 1, 2, 3.
+
+\subsection{glp\_del\_cols---delete columns from problem object}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_del_cols| deletes columns from the specified
+problem object. Ordinal numbers of columns to be deleted should be
+placed in locations \verb|num[1]|, \dots, \verb|num[ncs]|, where
+${\tt ncs}>0$.
+
+Note that deleting columns involves changing ordinal numbers of other
+columns remaining in the problem object. New ordinal numbers of the
+remaining columns are assigned under the assumption that the original
+order of columns is not changed. Let, for example, before deletion there
+be six columns $p$, $q$, $r$, $s$, $t$, $u$ with ordinal numbers 1, 2,
+3, 4, 5, 6, and let columns $p$, $q$, $s$ have been deleted. Then after
+deletion the remaining columns $r$, $t$, $u$ are assigned new ordinal
+numbers 1, 2, 3.
+
+\subsection{glp\_copy\_prob---copy problem object content}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_copy_prob| copies the content of the problem
+object \verb|prob| to the problem object \verb|dest|.
+
+The parameter \verb|names| is a flag. If it is \verb|GLP_ON|,
+the routine also copies all symbolic names; otherwise, if it is
+\verb|GLP_OFF|, no symbolic names are copied.
+
+\newpage
+
+\subsection{glp\_erase\_prob---erase problem object content}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_erase_prob(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_erase_prob| erases the content of the specified
+problem object. The effect of this operation is the same as if the
+problem object would be deleted with the routine \verb|glp_delete_prob|
+and then created anew with the routine \verb|glp_create_prob|, with the
+only exception that the handle (pointer) to the problem object remains
+valid.
+
+\subsection{glp\_delete\_prob---delete problem object}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_delete_prob(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_delete_prob| deletes a problem object, which the
+parameter \verb|lp| points to, freeing all the memory allocated to this
+object.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Problem retrieving routines}
+
+\subsection{glp\_get\_prob\_name---retrieve problem name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+const char *glp_get_prob_name(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_prob_name| returns a pointer to an internal
+buffer, which contains symbolic name of the problem. However, if the
+problem has no assigned name, the routine returns \verb|NULL|.
+
+\subsection{glp\_get\_obj\_name---retrieve objective function name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+const char *glp_get_obj_name(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_obj_name| returns a pointer to an internal
+buffer, which contains symbolic name assigned to the objective
+function. However, if the objective function has no assigned name, the
+routine returns \verb|NULL|.
+
+\subsection{glp\_get\_obj\_dir---retrieve optimization direction flag}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_obj_dir(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_obj_dir| returns the optimization direction
+flag (i.e. ``sense'' of the objective function):
+
+\begin{tabular}{@{}ll}
+\verb|GLP_MIN| & minimization; \\
+\verb|GLP_MAX| & maximization. \\
+\end{tabular}
+
+\pagebreak
+
+\subsection{glp\_get\_num\_rows---retrieve number of rows}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_num_rows(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_num_rows| returns the current number of rows
+in the specified problem object.
+
+\subsection{glp\_get\_num\_cols---retrieve number of columns}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_num_cols(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_num_cols| returns the current number of
+columns the specified problem object.
+
+\subsection{glp\_get\_row\_name---retrieve row name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+const char *glp_get_row_name(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_name| returns a pointer to an internal
+buffer, which contains a symbolic name assigned to \verb|i|-th row.
+However, if the row has no assigned name, the routine returns
+\verb|NULL|.
+
+\subsection{glp\_get\_col\_name---retrieve column name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+const char *glp_get_col_name(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_name| returns a pointer to an internal
+buffer, which contains a symbolic name assigned to \verb|j|-th column.
+However, if the column has no assigned name, the routine returns
+\verb|NULL|.
+
+\subsection{glp\_get\_row\_type---retrieve row type}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_row_type(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_type| returns the type of \verb|i|-th
+row, i.e. the type of corresponding auxiliary variable, as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_FR| & free (unbounded) variable; \\
+\verb|GLP_LO| & variable with lower bound; \\
+\verb|GLP_UP| & variable with upper bound; \\
+\verb|GLP_DB| & double-bounded variable; \\
+\verb|GLP_FX| & fixed variable. \\
+\end{tabular}
+
+\subsection{glp\_get\_row\_lb---retrieve row lower bound}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_row_lb(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_lb| returns the lower bound of
+\verb|i|-th row, i.e. the lower bound of corresponding auxiliary
+variable. However, if the row has no lower bound, the routine returns
+\verb|-DBL_MAX|.
+
+\subsection{glp\_get\_row\_ub---retrieve row upper bound}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_row_ub(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_ub| returns the upper bound of
+\verb|i|-th row, i.e. the upper bound of corresponding auxiliary
+variable. However, if the row has no upper bound, the routine returns
+\verb|+DBL_MAX|.
+
+\subsection{glp\_get\_col\_type---retrieve column type}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_col_type(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_type| returns the type of \verb|j|-th
+column, i.e. the type of corresponding structural variable, as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_FR| & free (unbounded) variable; \\
+\verb|GLP_LO| & variable with lower bound; \\
+\verb|GLP_UP| & variable with upper bound; \\
+\verb|GLP_DB| & double-bounded variable; \\
+\verb|GLP_FX| & fixed variable. \\
+\end{tabular}
+
+\subsection{glp\_get\_col\_lb---retrieve column lower bound}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_col_lb(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_lb| returns the lower bound of
+\verb|j|-th column, i.e. the lower bound of corresponding structural
+variable. However, if the column has no lower bound, the routine returns
+\verb|-DBL_MAX|.
+
+\subsection{glp\_get\_col\_ub---retrieve column upper bound}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_col_ub(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_ub| returns the upper bound of
+\verb|j|-th column, i.e. the upper bound of corresponding structural
+variable. However, if the column has no upper bound, the routine returns
+\verb|+DBL_MAX|.
+
+\subsection{glp\_get\_obj\_coef---retrieve objective coefficient or\\
+constant term}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_obj_coef(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_obj_coef| returns the objective coefficient
+at \verb|j|-th structural variable (column).
+
+If the parameter \verb|j| is 0, the routine returns the constant term
+(``shift'') of the objective function.
+
+\subsection{glp\_get\_num\_nz---retrieve number of constraint
+coefficients}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_num_nz(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_num_nz| returns the number of non-zero
+elements in the constraint matrix of the specified problem object.
+
+\subsection{glp\_get\_mat\_row---retrieve row of the constraint
+matrix}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_mat_row(glp_prob *lp, int i, int ind[],
+      double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_get_mat_row| scans (non-zero) elements of
+\verb|i|-th row of the constraint matrix of the specified problem object
+and stores their column indices and numeric values to locations
+\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
+\verb|val[len]|, respectively, where $0\leq{\tt len}\leq n$ is the
+number of elements in $i$-th row, $n$ is the number of columns.
+
+The parameter \verb|ind| and/or \verb|val| can be specified as
+\verb|NULL|, in which case corresponding information is not stored.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_mat_row| returns the length \verb|len|, i.e.
+the number of (non-zero) elements in \verb|i|-th row.
+
+\subsection{glp\_get\_mat\_col---retrieve column of the constraint\\
+matrix}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_mat_col(glp_prob *lp, int j, int ind[],
+      double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_get_mat_col| scans (non-zero) elements of
+\verb|j|-th column of the constraint matrix of the specified problem
+object and stores their row indices and numeric values to locations
+\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
+\verb|val[len]|, respectively, where $0\leq{\tt len}\leq m$ is the
+number of elements in $j$-th column, $m$ is the number of rows.
+
+The parameter \verb|ind| and/or \verb|val| can be specified as
+\verb|NULL|, in which case corresponding information is not stored.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_mat_col| returns the length \verb|len|, i.e.
+the number of (non-zero) elements in \verb|j|-th column.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Row and column searching routines}
+
+\subsection{glp\_create\_index---create the name index}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_create_index(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_create_index| creates the name index for the
+specified problem object. The name index is an auxiliary data structure,
+which is intended to quickly (i.e. for logarithmic time) find rows and
+columns by their names.
+
+This routine can be called at any time. If the name index already
+exists, the routine does nothing.
+
+\subsection{glp\_find\_row---find row by its name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_find_row(glp_prob *lp, const char *name);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_find_row| returns the ordinal number of a row,
+which is assigned (by the routine \verb|glp_set_row_name|) the specified
+symbolic \verb|name|. If no such row exists, the routine returns 0.
+
+\subsection{glp\_find\_col---find column by its name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_find_col(glp_prob *lp, const char *name);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_find_col| returns the ordinal number of a column,
+which is assigned (by the routine \verb|glp_set_col_name|) the specified
+symbolic \verb|name|. If no such column exists, the routine returns 0.
+
+\subsection{glp\_delete\_index---delete the name index}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_delete_index(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_delete_index| deletes the name index previously
+created by the routine \verb|glp_create_index| and frees the memory
+allocated to this auxiliary data structure.
+
+This routine can be called at any time. If the name index does not
+exist, the routine does nothing.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Problem scaling routines}
+
+\subsection{Background}
+
+In GLPK the {\it scaling} means a linear transformation applied to the
+constraint matrix to improve its numerical properties.\footnote{In many
+cases a proper scaling allows making the constraint matrix to be better
+conditioned, i.e. decreasing its condition number, that makes
+computations numerically more stable.}
+
+The main equality is the following:
+$$\widetilde{A}=RAS,\eqno(2.1)$$
+where $A=(a_{ij})$ is the original constraint matrix, $R=(r_{ii})>0$ is
+a diagonal matrix used to scale rows (constraints), $S=(s_{jj})>0$ is a
+diagonal matrix used to scale columns (variables), $\widetilde{A}$ is
+the scaled constraint matrix.
+
+From (2.1) it follows that in the {\it scaled} problem instance each
+original constraint coefficient $a_{ij}$ is replaced by corresponding
+scaled constraint coefficient:
+$$\widetilde{a}_{ij}=r_{ii}a_{ij}s_{jj}.\eqno(2.2)$$
+
+Note that the scaling is performed internally and therefore
+transparently to the user. This means that on API level the user always
+deal with unscaled data.
+
+Scale factors $r_{ii}$ and $s_{jj}$ can be set or changed at any time
+either directly by the application program in a problem specific way
+(with the routines \verb|glp_set_rii| and \verb|glp_set_sjj|), or by
+some API routines intended for automatic scaling.
+
+\subsection{glp\_set\_rii---set (change) row scale factor}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_rii(glp_prob *lp, int i, double rii);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_rii| sets (changes) the scale factor $r_{ii}$
+for $i$-th row of the specified problem object.
+
+\subsection{glp\_set\_sjj---set (change) column scale factor}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_sjj(glp_prob *lp, int j, double sjj);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_sjj| sets (changes) the scale factor $s_{jj}$
+for $j$-th column of the specified problem object.
+
+\subsection{glp\_get\_rii---retrieve row scale factor}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_rii(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_rii| returns current scale factor $r_{ii}$ for
+$i$-th row of the specified problem object.
+
+\subsection{glp\_get\_sjj---retrieve column scale factor}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_sjj(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_sjj| returns current scale factor $s_{jj}$ for
+$j$-th column of the specified problem object.
+
+\subsection{glp\_scale\_prob---scale problem data}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_scale_prob(glp_prob *lp, int flags);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_scale_prob| performs automatic scaling of problem
+data for the specified problem object.
+
+The parameter \verb|flags| specifies scaling options used by the
+routine. The options can be combined with the bitwise OR operator and
+may be the following:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_SF_GM| & perform geometric mean scaling;\\
+\verb|GLP_SF_EQ| & perform equilibration scaling;\\
+\verb|GLP_SF_2N| & round scale factors to nearest power of two;\\
+\verb|GLP_SF_SKIP| & skip scaling, if the problem is well scaled.\\
+\end{tabular}
+
+The parameter \verb|flags| may be specified as \verb|GLP_SF_AUTO|, in
+which case the routine chooses the scaling options automatically.
+
+\subsection{glp\_unscale\_prob---unscale problem data}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_unscale_prob(glp_prob *lp);
+\end{verbatim}
+
+The routine \verb|glp_unscale_prob| performs unscaling of problem data
+for the specified problem object.
+
+``Unscaling'' means replacing the current scaling matrices $R$ and $S$
+by unity matrices that cancels the scaling effect.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{LP basis constructing routines}
+
+\subsection{Background}
+
+To start the search the simplex method needs a valid initial basis. In
+GLPK the basis is completely defined by a set of {\it statuses} assigned
+to {\it all} (auxiliary and structural) variables, where the status may
+be one of the following:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_BS| & basic variable;\\
+\verb|GLP_NL| & non-basic variable having active lower bound;\\
+\verb|GLP_NU| & non-basic variable having active upper bound;\\
+\verb|GLP_NF| & non-basic free variable;\\
+\verb|GLP_NS| & non-basic fixed variable.\\
+\end{tabular}
+
+The basis is {\it valid}, if the basis matrix, which is a matrix built
+of columns of the augmented constraint matrix $(I\:|-A)$ corresponding
+to basic variables, is non-singular. This, in particular, means that
+the number of basic variables must be the same as the number of rows in
+the problem object. (For more details see Section \ref{lpbasis}, page
+\pageref{lpbasis}.)
+
+Any initial basis may be constructed (or restored) with the API
+routines \verb|glp_set_row_stat| and \verb|glp_set_col_stat| by
+assigning appropriate statuses to auxiliary and structural variables.
+Another way to construct an initial basis is to use API routines like
+\verb|glp_adv_basis|, which implement so called
+{\it crashing}.\footnote{This term is from early linear programming
+systems and means a heuristic to construct a valid initial basis.} Note
+that on normal exit the simplex solver remains the basis valid, so in
+case of reoptimization there is no need to construct an initial basis
+from scratch.
+
+\subsection{glp\_set\_row\_stat---set (change) row status}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_row_stat(glp_prob *lp, int i, int stat);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_row_stat| sets (changes) the current status
+of \verb|i|-th row (auxiliary variable) as specified by the parameter
+\verb|stat|:
+
+\begin{tabular}{@{}lp{104.2mm}@{}}
+\verb|GLP_BS| & make the row basic (make the constraint inactive); \\
+\verb|GLP_NL| & make the row non-basic (make the constraint active); \\
+\end{tabular}
+
+\newpage
+
+\begin{tabular}{@{}lp{104.2mm}@{}}
+\verb|GLP_NU| & make the row non-basic and set it to the upper bound;
+   if the row is not double-bounded, this status is equivalent to
+   \verb|GLP_NL| (only in the case of this routine); \\
+\verb|GLP_NF| & the same as \verb|GLP_NL| (only in the case of this
+   routine); \\
+\verb|GLP_NS| & the same as \verb|GLP_NL| (only in the case of this
+   routine). \\
+\end{tabular}
+
+\subsection{glp\_set\_col\_stat---set (change) column status}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_col_stat(glp_prob *lp, int j, int stat);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_col_stat sets| (changes) the current status
+of \verb|j|-th column (structural variable) as specified by the
+parameter \verb|stat|:
+
+\begin{tabular}{@{}lp{104.2mm}@{}}
+\verb|GLP_BS| & make the column basic; \\
+\verb|GLP_NL| & make the column non-basic; \\
+\verb|GLP_NU| & make the column non-basic and set it to the upper
+   bound; if the column is not double-bounded, this status is equivalent
+   to \verb|GLP_NL| (only in the case of this routine); \\
+\verb|GLP_NF| & the same as \verb|GLP_NL| (only in the case of this
+   routine); \\
+\verb|GLP_NS| & the same as \verb|GLP_NL| (only in the case of this
+   routine).
+\end{tabular}
+
+\subsection{glp\_std\_basis---construct standard initial LP basis}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_std_basis(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_std_basis| constructs the ``standard'' (trivial)
+initial LP basis for the specified problem object.
+
+In the ``standard'' LP basis all auxiliary variables (rows) are basic,
+and all structural variables (columns) are non-basic (so the
+corresponding basis matrix is unity).
+
+\newpage
+
+\subsection{glp\_adv\_basis---construct advanced initial LP basis}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_adv_basis(glp_prob *lp, int flags);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_adv_basis| constructs an advanced initial LP
+basis for the specified problem object.
+
+The parameter \verb|flags| is reserved for use in the future and must
+be specified as zero.
+
+In order to construct the advanced initial LP basis the routine does
+the following:
+
+1) includes in the basis all non-fixed auxiliary variables;
+
+2) includes in the basis as many non-fixed structural variables as
+possible keeping the triangular form of the basis matrix;
+
+3) includes in the basis appropriate (fixed) auxiliary variables to
+complete the basis.
+
+As a result the initial LP basis has as few fixed variables as possible
+and the corresponding basis matrix is triangular.
+
+\subsection{glp\_cpx\_basis---construct Bixby's initial LP basis}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_cpx_basis(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_cpx_basis| constructs an initial basis for the
+specified problem object with the algorithm proposed by
+R.~Bixby.\footnote{Robert E. Bixby, ``Implementing the Simplex Method:
+The Initial Basis.'' ORSA Journal on Computing, Vol. 4, No. 3, 1992,
+pp. 267-84.}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Simplex method routines}
+
+The {\it simplex method} is a well known efficient numerical procedure
+to solve LP problems.
+
+On each iteration the simplex method transforms the original system of
+equaility constraints (1.2) resolving them through different sets of
+variables to an equivalent system called {\it the simplex table} (or
+sometimes {\it the simplex tableau}), which has the following form:
+$$
+\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}r}
+z&=&d_1(x_N)_1&+&d_2(x_N)_2&+ \dots +&d_n(x_N)_n \\
+(x_B)_1&=&\xi_{11}(x_N)_1& +& \xi_{12}(x_N)_2& + \dots +&
+   \xi_{1n}(x_N)_n \\
+(x_B)_2&=& \xi_{21}(x_N)_1& +& \xi_{22}(x_N)_2& + \dots +&
+   \xi_{2n}(x_N)_n \\
+\multicolumn{7}{c}
+{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
+(x_B)_m&=&\xi_{m1}(x_N)_1& +& \xi_{m2}(x_N)_2& + \dots +&
+   \xi_{mn}(x_N)_n \\
+\end{array} \eqno (2.3)
+$$
+where: $(x_B)_1, (x_B)_2, \dots, (x_B)_m$ are basic variables;
+$(x_N)_1, (x_N)_2, \dots, (x_N)_n$ are non-basic variables;
+$d_1, d_2, \dots, d_n$ are reduced costs;
+$\xi_{11}, \xi_{12}, \dots, \xi_{mn}$ are coefficients of the
+simplex table. (May note that the original LP problem (1.1)---(1.3) also
+has the form of a simplex table, where all equalities are resolved
+through auxiliary variables.)
+
+From the linear programming theory it is known that if an optimal
+solution of the LP problem (1.1)---(1.3) exists, it can always be
+written in the form (2.3), where non-basic variables are set on their
+bounds while values of the objective function and basic variables are
+determined by the corresponding equalities of the simplex table.
+
+A set of values of all basic and non-basic variables determined by the
+simplex table is called {\it basic solution}. If all basic variables are
+within their bounds, the basic solution is called {\it (primal)
+feasible}, otherwise it is called {\it (primal) infeasible}. A feasible
+basic solution, which provides a smallest (in case of minimization) or
+a largest (in case of maximization) value of the objective function is
+called {\it optimal}. Therefore, for solving LP problem the simplex
+method tries to find its optimal basic solution.
+
+Primal feasibility of some basic solution may be stated by simple
+checking if all basic variables are within their bounds. Basic solution
+is optimal if additionally the following optimality conditions are
+satisfied for all non-basic variables:
+\begin{center}
+\begin{tabular}{lcc}
+Status of $(x_N)_j$ & Minimization & Maximization \\
+\hline
+$(x_N)_j$ is free & $d_j = 0$ & $d_j = 0$ \\
+$(x_N)_j$ is on its lower bound & $d_j \geq 0$ & $d_j \leq 0$ \\
+$(x_N)_j$ is on its upper bound & $d_j \leq 0$ & $d_j \geq 0$ \\
+\end{tabular}
+\end{center}
+In other words, basic solution is optimal if there is no non-basic
+variable, which changing in the feasible direction (i.e. increasing if
+it is free or on its lower bound, or decreasing if it is free or on its
+upper bound) can improve (i.e. decrease in case of minimization or
+increase in case of maximization) the objective function.
+
+If all non-basic variables satisfy to the optimality conditions shown
+above (independently on whether basic variables are within their bounds
+or not), the basic solution is called {\it dual feasible}, otherwise it
+is called {\it dual infeasible}.
+
+It may happen that some LP problem has no primal feasible solution due
+to incorrect formulation---this means that its constraints conflict
+with each other. It also may happen that some LP problem has unbounded
+solution again due to incorrect formulation---this means that some
+non-basic variable can improve the objective function, i.e. the
+optimality conditions are violated, and at the same time this variable
+can infinitely change in the feasible direction meeting no resistance
+from basic variables. (May note that in the latter case the LP problem
+has no dual feasible solution.)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{glp\_simplex---solve LP problem with the primal or dual
+simplex method}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_simplex(glp_prob *lp, const glp_smcp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_simplex| is a driver to the LP solver based on
+the simplex method. This routine retrieves problem data from the
+specified problem object, calls the solver to solve the problem
+instance, and stores results of computations back into the problem
+object.
+
+The simplex solver has a set of control parameters. Values of the
+control parameters can be passed in the structure \verb|glp_smcp|,
+which the parameter \verb|parm| points to. For detailed description of
+this structure see paragraph ``Control parameters'' below.
+Before specifying some control parameters the application program
+should initialize the structure \verb|glp_smcp| by default values of
+all control parameters using the routine \verb|glp_init_smcp| (see the
+next subsection). This is needed for backward compatibility, because in
+the future there may appear new members in the structure
+\verb|glp_smcp|.
+
+The parameter \verb|parm| can be specified as \verb|NULL|, in which
+case the solver uses default settings.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The LP problem instance has been successfully solved. (This code
+does {\it not} necessarily mean that the solver has found optimal
+solution. It only means that the solution process was successful.) \\
+\verb|GLP_EBADB| & Unable to start the search, because the initial basis
+specified in the problem object is invalid---the number of basic
+(auxiliary and structural) variables is not the same as the number of
+rows in the problem object.\\
+\verb|GLP_ESING| & Unable to start the search, because the basis matrix
+corresponding to the initial basis is singular within the working
+precision.\\
+\verb|GLP_ECOND| & Unable to start the search, because the basis matrix
+corresponding to the initial basis is ill-conditioned, i.e. its
+condition number is too large.\\
+\verb|GLP_EBOUND| & Unable to start the search, because some
+double-bounded (auxiliary or structural) variables have incorrect
+bounds.\\
+\verb|GLP_EFAIL| & The search was prematurely terminated due to the
+solver failure.\\
+\verb|GLP_EOBJLL| & The search was prematurely terminated, because the
+objective function being maximized has reached its lower limit and
+continues decreasing (the dual simplex only).\\
+\verb|GLP_EOBJUL| & The search was prematurely terminated, because the
+objective function being minimized has reached its upper limit and
+continues increasing (the dual simplex only).\\
+\verb|GLP_EITLIM| & The search was prematurely terminated, because the
+simplex iteration limit has been exceeded.\\
+\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
+time limit has been exceeded.\\
+\verb|GLP_ENOPFS| & The LP problem instance has no primal feasible
+solution (only if the LP presolver is used).\\
+\verb|GLP_ENODFS| & The LP problem instance has no dual feasible
+solution (only if the LP presolver is used).\\
+\end{tabular}
+
+\subsubsection*{Built-in LP presolver}
+
+The simplex solver has {\it built-in LP presolver}. It is a subprogram
+that transforms the original LP problem specified in the problem object
+to an equivalent LP problem, which may be easier for solving with the
+simplex method than the original one. This is attained mainly due to
+reducing the problem size and improving its numeric properties (for
+example, by removing some inactive constraints or by fixing some
+non-basic variables). Once the transformed LP problem has been solved,
+the presolver transforms its basic solution back to the corresponding
+basic solution of the original problem.
+
+Presolving is an optional feature of the routine \verb|glp_simplex|,
+and by default it is disabled. In order to enable the LP presolver the
+control parameter \verb|presolve| should be set to \verb|GLP_ON| (see
+paragraph ``Control parameters'' below). Presolving may be used when
+the problem instance is solved for the first time. However, on
+performing re-optimization the presolver should be disabled.
+
+The presolving procedure is transparent to the API user in the sense
+that all necessary processing is performed internally, and a basic
+solution of the original problem recovered by the presolver is the same
+as if it were computed directly, i.e. without presolving.
+
+Note that the presolver is able to recover only optimal solutions. If
+a computed solution is infeasible or non-optimal, the corresponding
+solution of the original problem cannot be recovered and therefore
+remains undefined. If you need to know a basic solution even if it is
+infeasible or non-optimal, the presolver should be disabled.
+
+\subsubsection*{Terminal output}
+
+Solving large problem instances may take a long time, so the solver
+reports some information about the current basic solution, which is sent
+to the terminal. This information has the following format:
+
+\begin{verbatim}
+nnn:  obj = xxx  infeas = yyy (ddd)
+\end{verbatim}
+
+\noindent
+where: `\verb|nnn|' is the iteration number, `\verb|xxx|' is the
+current value of the objective function (it is is unscaled and has
+correct sign); `\verb|yyy|' is the current sum of primal or dual
+infeasibilities (it is scaled and therefore may be used only for visual
+estimating), `\verb|ddd|' is the current number of fixed basic
+variables.
+
+The symbol preceding the iteration number indicates which phase of the
+simplex method is in effect:
+
+{\it Blank} means that the solver is searching for primal feasible
+solution using the primal simplex or for dual feasible solution using
+the dual simplex;
+
+{\it Asterisk} (\verb|*|) means that the solver is searching for
+optimal solution using the primal simplex;
+
+{\it Vertical dash} (\verb/|/) means that the solver is searching for
+optimal solution using the dual simplex.
+
+\subsubsection*{Control parameters}
+
+This paragraph describes all control parameters currently used in the
+simplex solver. Symbolic names of control parameters are names of
+corresponding members in the structure \verb|glp_smcp|.
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
+\\
+&Message level for terminal output:\\
+&\verb|GLP_MSG_OFF|---no output;\\
+&\verb|GLP_MSG_ERR|---error and warning messages only;\\
+&\verb|GLP_MSG_ON |---normal output;\\
+&\verb|GLP_MSG_ALL|---full output (including informational messages).
+\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int meth} (default: {\tt GLP\_PRIMAL})}
+\\
+&Simplex method option:\\
+&\verb|GLP_PRIMAL|---use two-phase primal simplex;\\
+&\verb|GLP_DUAL  |---use two-phase dual simplex;\\
+&\verb|GLP_DUALP |---use two-phase dual simplex, and if it fails,
+switch to the\\
+&\verb|            |$\:$ primal simplex.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int pricing} (default: {\tt GLP\_PT\_PSE})}
+\\
+&Pricing technique:\\
+&\verb|GLP_PT_STD|---standard (textbook);\\
+&\verb|GLP_PT_PSE|---projected steepest edge.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int r\_test} (default: {\tt GLP\_RT\_HAR})}
+\\
+&Ratio test technique:\\
+&\verb|GLP_RT_STD|---standard (textbook);\\
+&\verb|GLP_RT_HAR|---Harris' two-pass ratio test.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double tol\_bnd} (default: {\tt 1e-7})}
+\\
+&Tolerance used to check if the basic solution is primal feasible.
+(Do not change this parameter without detailed understanding its
+purpose.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double tol\_dj} (default: {\tt 1e-7})}
+\\
+&Tolerance used to check if the basic solution is dual feasible.
+(Do not change this parameter without detailed understanding its
+purpose.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double tol\_piv} (default: {\tt 1e-10})}
+\\
+&Tolerance used to choose eligble pivotal elements of the simplex table.
+(Do not change this parameter without detailed understanding its
+purpose.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double obj\_ll} (default: {\tt -DBL\_MAX})}
+\\
+&Lower limit of the objective function. If the objective function
+reaches this limit and continues decreasing, the solver terminates the
+search. (Used in the dual simplex only.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double obj\_ul} (default: {\tt +DBL\_MAX})}
+\\
+&Upper limit of the objective function. If the objective function
+reaches this limit and continues increasing, the solver terminates the
+search. (Used in the dual simplex only.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int it\_lim} (default: {\tt INT\_MAX})}
+\\
+&Simplex iteration limit.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int tm\_lim} (default: {\tt INT\_MAX})}
+\\
+&Searching time limit, in milliseconds.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int out\_frq} (default: {\tt 500})}
+\\
+&Output frequency, in iterations. This parameter specifies how
+frequently the solver sends information about the solution process to
+the terminal.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int out\_dly} (default: {\tt 0})}
+\\
+&Output delay, in milliseconds. This parameter specifies how long the
+solver should delay sending information about the solution process to
+the terminal.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int presolve} (default: {\tt GLP\_OFF})}
+\\
+&LP presolver option:\\
+&\verb|GLP_ON |---enable using the LP presolver;\\
+&\verb|GLP_OFF|---disable using the LP presolver.\\
+\end{tabular}
+
+\subsubsection*{Example 1}
+
+The following main program reads LP problem instance in fixed MPS
+format from file \verb|25fv47.mps|,\footnote{This instance in fixed MPS
+format can be found in the Netlib LP collection; see
+{\tt ftp://ftp.netlib.org/lp/data/}.} constructs an advanced initial
+basis, solves the instance with the primal simplex method (by default),
+and writes the solution to file \verb|25fv47.txt|.
+
+\newpage
+
+\begin{footnotesize}
+\begin{verbatim}
+/* spxsamp1.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *P;
+      P = glp_create_prob();
+      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
+      glp_adv_basis(P, 0);
+      glp_simplex(P, NULL);
+      glp_print_sol(P, "25fv47.txt");
+      glp_delete_prob(P);
+      return 0;
+}
+
+/* eof */
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+Below here is shown the terminal output from this example program.
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading problem data from `25fv47.mps'...
+Problem: 25FV47
+Objective: R0000
+822 rows, 1571 columns, 11127 non-zeros
+6919 records were read
+Crashing...
+Size of triangular part = 799
+      0: obj =   1.627307307e+04  infeas =  5.194e+04 (23)
+    200: obj =   1.474901610e+04  infeas =  1.233e+04 (19)
+    400: obj =   1.343909995e+04  infeas =  3.648e+03 (13)
+    600: obj =   1.756052217e+04  infeas =  4.179e+02 (7)
+*   775: obj =   1.789251591e+04  infeas =  4.982e-14 (1)
+*   800: obj =   1.663354510e+04  infeas =  2.857e-14 (1)
+*  1000: obj =   1.024935068e+04  infeas =  1.958e-12 (1)
+*  1200: obj =   7.860174791e+03  infeas =  2.810e-29 (1)
+*  1400: obj =   6.642378184e+03  infeas =  2.036e-16 (1)
+*  1600: obj =   6.037014568e+03  infeas =  0.000e+00 (1)
+*  1800: obj =   5.662171307e+03  infeas =  6.447e-15 (1)
+*  2000: obj =   5.528146165e+03  infeas =  9.764e-13 (1)
+*  2125: obj =   5.501845888e+03  infeas =  0.000e+00 (1)
+OPTIMAL SOLUTION FOUND
+Writing basic solution to `25fv47.txt'...
+\end{verbatim}
+\end{footnotesize}
+
+\newpage
+
+\subsubsection*{Example 2}
+
+The following main program solves the same LP problem instance as in
+Example 1 above, however, it uses the dual simplex method, which starts
+from the standard initial basis.
+
+\begin{footnotesize}
+\begin{verbatim}
+/* spxsamp2.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *P;
+      glp_smcp parm;
+      P = glp_create_prob();
+      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
+      glp_init_smcp(&parm);
+      parm.meth = GLP_DUAL;
+      glp_simplex(P, &parm);
+      glp_print_sol(P, "25fv47.txt");
+      glp_delete_prob(P);
+      return 0;
+}
+
+/* eof */
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+Below here is shown the terminal output from this example program.
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading problem data from `25fv47.mps'...
+Problem: 25FV47
+Objective: R0000
+822 rows, 1571 columns, 11127 non-zeros
+6919 records were read
+      0:                          infeas =  1.223e+03 (516)
+    200:                          infeas =  7.000e+00 (471)
+    240:                          infeas =  1.106e-14 (461)
+|   400: obj =  -5.394267152e+03  infeas =  5.571e-16 (391)
+|   600: obj =  -4.586395752e+03  infeas =  1.389e-15 (340)
+|   800: obj =  -4.158268146e+03  infeas =  1.640e-15 (264)
+|  1000: obj =  -3.725320045e+03  infeas =  5.181e-15 (245)
+|  1200: obj =  -3.104802163e+03  infeas =  1.019e-14 (210)
+|  1400: obj =  -2.584190499e+03  infeas =  8.865e-15 (178)
+|  1600: obj =  -2.073852927e+03  infeas =  7.867e-15 (142)
+|  1800: obj =  -1.164037407e+03  infeas =  8.792e-15 (109)
+|  2000: obj =  -4.370590250e+02  infeas =  2.591e-14 (85)
+|  2200: obj =   1.068240144e+03  infeas =  1.025e-13 (70)
+|  2400: obj =   1.607481126e+03  infeas =  3.272e-14 (67)
+|  2600: obj =   3.038230551e+03  infeas =  4.850e-14 (52)
+|  2800: obj =   4.316238187e+03  infeas =  2.622e-14 (36)
+|  3000: obj =   5.443842629e+03  infeas =  3.976e-15 (11)
+|  3060: obj =   5.501845888e+03  infeas =  8.806e-15 (2)
+OPTIMAL SOLUTION FOUND
+Writing basic solution to `25fv47.txt'...
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_exact---solve LP problem in exact arithmetic}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_exact(glp_prob *lp, const glp_smcp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_exact| is a tentative implementation of the
+primal two-phase simplex method based on exact (rational) arithmetic.
+It is similar to the routine \verb|glp_simplex|, however, for all
+internal computations it uses arithmetic of rational numbers, which is
+exact in mathematical sense, i.e. free of round-off errors unlike
+floating-point arithmetic.
+
+Note that the routine \verb|glp_exact| uses only two control parameters
+passed in the structure \verb|glp_smcp|, namely, \verb|it_lim| and
+\verb|tm_lim|.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The LP problem instance has been successfully solved. (This code
+does {\it not} necessarily mean that the solver has found optimal
+solution. It only means that the solution process was successful.) \\
+\verb|GLP_EBADB| & Unable to start the search, because the initial basis
+specified in the problem object is invalid---the number of basic
+(auxiliary and structural) variables is not the same as the number of
+rows in the problem object.\\
+\verb|GLP_ESING| & Unable to start the search, because the basis matrix
+corresponding to the initial basis is exactly singular.\\
+\verb|GLP_EBOUND| & Unable to start the search, because some
+double-bounded (auxiliary or structural) variables have incorrect
+bounds.\\
+\verb|GLP_EFAIL| & The problem instance has no rows/columns.\\
+\verb|GLP_EITLIM| & The search was prematurely terminated, because the
+simplex iteration limit has been exceeded.\\
+\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
+time limit has been exceeded.\\
+\end{tabular}
+
+\subsubsection*{Comments}
+
+Computations in exact arithmetic are very time consuming, so solving
+LP problem with the routine \verb|glp_exact| from the very beginning is
+not a good idea. It is much better at first to find an optimal basis
+with the routine \verb|glp_simplex| and only then to call
+\verb|glp_exact|, in which case only a few simplex iterations need to
+be performed in exact arithmetic.
+
+\subsection{glp\_init\_smcp---initialize simplex solver control
+parameters}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_init_smcp(glp_smcp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_init_smcp| initializes control parameters, which
+are used by the simplex solver, with default values.
+
+Default values of the control parameters are stored in a \verb|glp_smcp|
+structure, which the parameter \verb|parm| points to.
+
+\subsection{glp\_get\_status---determine generic status of basic
+solution}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_status(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_status| reports the generic status of the
+current basic solution for the specified problem object as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_OPT|    & solution is optimal; \\
+\verb|GLP_FEAS|   & solution is feasible; \\
+\verb|GLP_INFEAS| & solution is infeasible; \\
+\verb|GLP_NOFEAS| & problem has no feasible solution; \\
+\verb|GLP_UNBND|  & problem has unbounded solution; \\
+\verb|GLP_UNDEF|  & solution is undefined. \\
+\end{tabular}
+
+More detailed information about the status of basic solution can be
+retrieved with the routines \verb|glp_get_prim_stat| and
+\verb|glp_get_dual_stat|.
+
+\newpage
+
+\subsection{glp\_get\_prim\_stat---retrieve status of primal basic
+solution}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_prim_stat(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_prim_stat| reports the status of the primal
+basic solution for the specified problem object as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_UNDEF|  & primal solution is undefined; \\
+\verb|GLP_FEAS|   & primal solution is feasible; \\
+\verb|GLP_INFEAS| & primal solution is infeasible; \\
+\verb|GLP_NOFEAS| & no primal feasible solution exists. \\
+\end{tabular}
+
+\subsection{glp\_get\_dual\_stat---retrieve status of dual basic
+solution}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_dual_stat(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_dual_stat| reports the status of the dual
+basic solution for the specified problem object as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_UNDEF|  & dual solution is undefined; \\
+\verb|GLP_FEAS|   & dual solution is feasible; \\
+\verb|GLP_INFEAS| & dual solution is infeasible; \\
+\verb|GLP_NOFEAS| & no dual feasible solution exists. \\
+\end{tabular}
+
+\subsection{glp\_get\_obj\_val---retrieve objective value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_obj_val(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_obj_val| returns current value of the
+objective function.
+
+\subsection{glp\_get\_row\_stat---retrieve row status}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_row_stat(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_stat| returns current status assigned to
+the auxiliary variable associated with \verb|i|-th row as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_BS| & basic variable; \\
+\verb|GLP_NL| & non-basic variable on its lower bound; \\
+\verb|GLP_NU| & non-basic variable on its upper bound; \\
+\verb|GLP_NF| & non-basic free (unbounded) variable; \\
+\verb|GLP_NS| & non-basic fixed variable. \\
+\end{tabular}
+
+\subsection{glp\_get\_row\_prim---retrieve row primal value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_row_prim(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_prim| returns primal value of the
+auxiliary variable associated with \verb|i|-th row.
+
+\subsection{glp\_get\_row\_dual---retrieve row dual value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_row_dual(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_dual| returns dual value (i.e. reduced
+cost) of the auxiliary variable associated with \verb|i|-th row.
+
+\newpage
+
+\subsection{glp\_get\_col\_stat---retrieve column status}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_col_stat(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_stat| returns current status assigned to
+the structural variable associated with \verb|j|-th column as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_BS| & basic variable; \\
+\verb|GLP_NL| & non-basic variable on its lower bound; \\
+\verb|GLP_NU| & non-basic variable on its upper bound; \\
+\verb|GLP_NF| & non-basic free (unbounded) variable; \\
+\verb|GLP_NS| & non-basic fixed variable. \\
+\end{tabular}
+
+\subsection{glp\_get\_col\_prim---retrieve column primal value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_col_prim(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_prim| returns primal value of the
+structural variable associated with \verb|j|-th column.
+
+\subsection{glp\_get\_col\_dual---retrieve column dual value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_get_col_dual(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_dual| returns dual value (i.e. reduced
+cost) of the structural variable associated with \verb|j|-th column.
+
+\newpage
+
+\subsection{glp\_get\_unbnd\_ray---determine variable causing\\
+unboundedness}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_unbnd_ray(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_unbnd_ray| returns the number $k$ of
+a variable, which causes primal or dual unboundedness.
+If $1\leq k\leq m$, it is $k$-th auxiliary variable, and if
+$m+1\leq k\leq m+n$, it is $(k-m)$-th structural variable, where $m$ is
+the number of rows, $n$ is the number of columns in the problem object.
+If such variable is not defined, the routine returns 0.
+
+\subsubsection*{Comments}
+
+If it is not exactly known which version of the simplex solver
+detected unboundedness, i.e. whether the unboundedness is primal or
+dual, it is sufficient to check the status of the variable
+with the routine \verb|glp_get_row_stat| or \verb|glp_get_col_stat|.
+If the variable is non-basic, the unboundedness is primal, otherwise,
+if the variable is basic, the unboundedness is dual (the latter case
+means that the problem has no primal feasible dolution).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Interior-point method routines}
+
+{\it Interior-point methods} (also known as {\it barrier methods}) are
+more modern and powerful numerical methods for large-scale linear
+programming. Such methods are especially efficient for very sparse LP
+problems and allow solving such problems much faster than the simplex
+method.
+
+In brief, the GLPK interior-point solver works as follows.
+
+At first, the solver transforms the original LP to a {\it working} LP
+in the standard format:
+
+\medskip
+
+\noindent
+\hspace{.5in} minimize
+$$z = c_1x_{m+1} + c_2x_{m+2} + \dots + c_nx_{m+n} + c_0 \eqno (2.4)$$
+\hspace{.5in} subject to linear constraints
+$$
+\begin{array}{r@{\:}c@{\:}r@{\:}c@{\:}r@{\:}c@{\:}l}
+a_{11}x_{m+1}&+&a_{12}x_{m+2}&+ \dots +&a_{1n}x_{m+n}&=&b_1 \\
+a_{21}x_{m+1}&+&a_{22}x_{m+2}&+ \dots +&a_{2n}x_{m+n}&=&b_2 \\
+\multicolumn{7}{c}
+{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .} \\
+a_{m1}x_{m+1}&+&a_{m2}x_{m+2}&+ \dots +&a_{mn}x_{m+n}&=&b_m \\
+\end{array} \eqno (2.5)
+$$
+\hspace{.5in} and non-negative variables
+$$x_1\geq 0,\ \ x_2\geq 0,\ \ \dots,\ \ x_n\geq 0 \eqno(2.6)$$
+where: $z$ is the objective function; $x_1$, \dots, $x_n$ are variables;
+$c_1$, \dots, $c_n$ are objective coefficients; $c_0$ is a constant term
+of the objective function;\linebreak $a_{11}$, \dots, $a_{mn}$ are
+constraint coefficients; $b_1$, \dots, $b_m$ are right-hand sides.
+
+Using vector and matrix notations the working LP (2.4)---(2.6) can be
+written as follows:
+$$z=c^Tx+c_0\ \rightarrow\ \min,\eqno(2.7)$$
+$$Ax=b,\eqno(2.8)$$
+$$x\geq 0,\eqno(2.9)$$
+where: $x=(x_j)$ is $n$-vector of variables, $c=(c_j)$ is $n$-vector of
+objective coefficients, $A=(a_{ij})$ is $m\times n$-matrix of
+constraint coefficients, and $b=(b_i)$ is $m$-vector of right-hand
+sides.
+
+Karush--Kuhn--Tucker optimality conditions for LP (2.7)---(2.9) are the
+following:
+
+\newpage
+
+$$Ax=b,\eqno(2.10)$$
+$$A^T\pi+\lambda=c,\eqno(2.11)$$
+$$\lambda^Tx=0,\eqno(2.12)$$
+$$x\geq 0,\ \ \lambda\geq 0,\eqno(2.13)$$
+where: $\pi$ is $m$-vector of Lagrange multipliers (dual variables) for
+equality constraints (2.8), $\lambda$ is $n$-vector of Lagrange
+multipliers (dual variables) for non-negativity constraints (2.9),
+(2.10) is the primal feasibility condition, (2.11) is the dual
+feasibility condition, (2.12) is the primal-dual complementarity
+condition, and (2.13) is the non-negativity conditions.
+
+The main idea of the primal-dual interior-point method is based on
+finding a point in the primal-dual space (i.e. in the space of all
+primal and dual variables $x$, $\pi$, and $\lambda$), which satisfies
+to all optimality conditions (2.10)---(2.13). Obviously, $x$-component
+of such point then provides an optimal solution to the working LP
+(2.7)---(2.9).
+
+To find the optimal point $(x^*,\pi^*,\lambda^*)$ the interior-point
+method attempts to solve the system of equations (2.10)---(2.12), which
+is closed in the sense that the number of variables $x_j$, $\pi_i$, and
+$\lambda_j$ and the number equations are the same and equal to $m+2n$.
+Due to condition (2.12) this system of equations is non-linear, so it
+can be solved with a version of {\it Newton's method} provided with
+additional rules to keep the current point within the positive orthant
+as required by the non-negativity conditions (2.13).
+
+Finally, once the optimal point $(x^*,\pi^*,\lambda^*)$ has been found,
+the solver performs inverse transformations to recover corresponding
+solution to the original LP passed to the solver from the application
+program.
+
+\subsection{glp\_interior---solve LP problem with the interior-point
+method}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_interior(glp_prob *P, const glp_iptcp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_interior| is a driver to the LP solver based on
+the primal-dual interior-point method. This routine retrieves problem
+data from the specified problem object, calls the solver to solve the
+problem instance, and stores results of computations back into the
+problem object.
+
+The interior-point solver has a set of control parameters. Values of
+the control parameters can be passed in the structure \verb|glp_iptcp|,
+which the parameter \verb|parm| points to. For detailed description of
+this structure see paragraph ``Control parameters'' below. Before
+specifying some control parameters the application program should
+initialize the structure \verb|glp_iptcp| by default values of all
+control parameters using the routine \verb|glp_init_iptcp| (see the
+next subsection). This is needed for backward compatibility, because in
+the future there may appear new members in the structure
+\verb|glp_iptcp|.
+
+The parameter \verb|parm| can be specified as \verb|NULL|, in which
+case the solver uses default settings.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The LP problem instance has been successfully solved. (This code
+does {\it not} necessarily mean that the solver has found optimal
+solution. It only means that the solution process was successful.) \\
+\verb|GLP_EFAIL| & The problem has no rows/columns.\\
+\verb|GLP_ENOCVG| & Very slow convergence or divergence.\\
+\verb|GLP_EITLIM| & Iteration limit exceeded.\\
+\verb|GLP_EINSTAB| & Numerical instability on solving Newtonian
+system.\\
+\end{tabular}
+
+\subsubsection*{Comments}
+
+The routine \verb|glp_interior| implements an easy version of
+the primal-dual interior-point method based on Mehrotra's
+technique.\footnote{S. Mehrotra. On the implementation of a primal-dual
+interior point method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.}
+
+Note that currently the GLPK interior-point solver does not include
+many important features, in particular:
+
+$\bullet$ it is not able to process dense columns. Thus, if the
+constraint matrix of the LP problem has dense columns, the solving
+process may be inefficient;
+
+$\bullet$ it has no features against numerical instability. For some
+LP problems premature termination may happen if the matrix $ADA^T$
+becomes singular or ill-conditioned;
+
+$\bullet$ it is not able to identify the optimal basis, which
+corresponds to the interior-point solution found.
+
+\newpage
+
+\subsubsection*{Terminal output}
+
+Solving large LP problems may take a long time, so the solver reports
+some information about every interior-point iteration,\footnote{Unlike
+the simplex method the interior point method usually needs 30---50
+iterations (independently on the problem size) in order to find an
+optimal solution.} which is sent to the terminal. This information has
+the following format:
+
+\begin{verbatim}
+nnn: obj = fff; rpi = ppp; rdi = ddd; gap = ggg
+\end{verbatim}
+
+\noindent where: \verb|nnn| is iteration number, \verb|fff| is the
+current value of the objective function (in the case of maximization it
+has wrong sign), \verb|ppp| is the current relative primal
+infeasibility (cf. (2.10)):
+$$\frac{\|Ax^{(k)}-b\|}{1+\|b\|},\eqno(2.14)$$
+\verb|ddd| is the current relative dual infeasibility (cf. (2.11)):
+$$\frac{\|A^T\pi^{(k)}+\lambda^{(k)}-c\|}{1+\|c\|},\eqno(2.15)$$
+\verb|ggg| is the current primal-dual gap (cf. (2.12)):
+$$\frac{|c^Tx^{(k)}-b^T\pi^{(k)}|}{1+|c^Tx^{(k)}|},\eqno(2.16)$$
+and $[x^{(k)},\pi^{(k)},\lambda^{(k)}]$ is the current point on $k$-th
+iteration, $k=0,1,2,\dots$\ . Note that all solution components are
+internally scaled, so information sent to the terminal is suitable only
+for visual inspection.
+
+\subsubsection*{Control parameters}
+
+This paragraph describes all control parameters currently used in the
+interior-point solver. Symbolic names of control parameters are names of
+corresponding members in the structure \verb|glp_iptcp|.
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
+\\
+&Message level for terminal output:\\
+&\verb|GLP_MSG_OFF|---no output;\\
+&\verb|GLP_MSG_ERR|---error and warning messages only;\\
+&\verb|GLP_MSG_ON |---normal output;\\
+&\verb|GLP_MSG_ALL|---full output (including informational messages).
+\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int ord\_alg} (default: {\tt GLP\_ORD\_AMD})}
+\\
+&Ordering algorithm used prior to Cholesky factorization:\\
+&\verb|GLP_ORD_NONE  |---use natural (original) ordering;\\
+&\verb|GLP_ORD_QMD   |---quotient minimum degree (QMD);\\
+&\verb|GLP_ORD_AMD   |---approximate minimum degree (AMD);\\
+&\verb|GLP_ORD_SYMAMD|---approximate minimum degree (SYMAMD).\\
+\end{tabular}
+
+\subsubsection*{Example}
+
+The following main program reads LP problem instance in fixed MPS
+format from file \verb|25fv47.mps|,\footnote{This instance in fixed MPS
+format can be found in the Netlib LP collection; see
+{\tt ftp://ftp.netlib.org/lp/data/}.} solves it with the interior-point
+solver, and writes the solution to file \verb|25fv47.txt|.
+
+\begin{footnotesize}
+\begin{verbatim}
+/* iptsamp.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *P;
+      P = glp_create_prob();
+      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
+      glp_interior(P, NULL);
+      glp_print_ipt(P, "25fv47.txt");
+      glp_delete_prob(P);
+      return 0;
+}
+
+/* eof */
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+Below here is shown the terminal output from this example program.
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading problem data from `25fv47.mps'...
+Problem: 25FV47
+Objective: R0000
+822 rows, 1571 columns, 11127 non-zeros
+6919 records were read
+Original LP has 822 row(s), 1571 column(s), and 11127 non-zero(s)
+Working LP has 821 row(s), 1876 column(s), and 10705 non-zero(s)
+Matrix A has 10705 non-zeros
+Matrix S = A*A' has 11895 non-zeros (upper triangle)
+Minimal degree ordering...
+Computing Cholesky factorization S = L'*L...
+Matrix L has 35411 non-zeros
+Guessing initial point...
+Optimization begins...
+  0: obj =   1.823377629e+05; rpi =  1.3e+01; rdi =  1.4e+01; gap =  9.3e-01
+  1: obj =   9.260045192e+04; rpi =  5.3e+00; rdi =  5.6e+00; gap =  6.8e+00
+  2: obj =   3.596999742e+04; rpi =  1.5e+00; rdi =  1.2e+00; gap =  1.8e+01
+  3: obj =   1.989627568e+04; rpi =  4.7e-01; rdi =  3.0e-01; gap =  1.9e+01
+  4: obj =   1.430215557e+04; rpi =  1.1e-01; rdi =  8.6e-02; gap =  1.4e+01
+  5: obj =   1.155716505e+04; rpi =  2.3e-02; rdi =  2.4e-02; gap =  6.8e+00
+  6: obj =   9.660273208e+03; rpi =  6.7e-03; rdi =  4.6e-03; gap =  3.9e+00
+  7: obj =   8.694348283e+03; rpi =  3.7e-03; rdi =  1.7e-03; gap =  2.0e+00
+  8: obj =   8.019543639e+03; rpi =  2.4e-03; rdi =  3.9e-04; gap =  1.0e+00
+  9: obj =   7.122676293e+03; rpi =  1.2e-03; rdi =  1.5e-04; gap =  6.6e-01
+ 10: obj =   6.514534518e+03; rpi =  6.1e-04; rdi =  4.3e-05; gap =  4.1e-01
+ 11: obj =   6.361572203e+03; rpi =  4.8e-04; rdi =  2.2e-05; gap =  3.0e-01
+ 12: obj =   6.203355508e+03; rpi =  3.2e-04; rdi =  1.7e-05; gap =  2.6e-01
+ 13: obj =   6.032943411e+03; rpi =  2.0e-04; rdi =  9.3e-06; gap =  2.1e-01
+ 14: obj =   5.796553021e+03; rpi =  9.8e-05; rdi =  3.2e-06; gap =  1.0e-01
+ 15: obj =   5.667032431e+03; rpi =  4.4e-05; rdi =  1.1e-06; gap =  5.6e-02
+ 16: obj =   5.613911867e+03; rpi =  2.5e-05; rdi =  4.1e-07; gap =  3.5e-02
+ 17: obj =   5.560572626e+03; rpi =  9.9e-06; rdi =  2.3e-07; gap =  2.1e-02
+ 18: obj =   5.537276001e+03; rpi =  5.5e-06; rdi =  8.4e-08; gap =  1.1e-02
+ 19: obj =   5.522746942e+03; rpi =  2.2e-06; rdi =  4.0e-08; gap =  6.7e-03
+ 20: obj =   5.509956679e+03; rpi =  7.5e-07; rdi =  1.8e-08; gap =  2.9e-03
+ 21: obj =   5.504571733e+03; rpi =  1.6e-07; rdi =  5.8e-09; gap =  1.1e-03
+ 22: obj =   5.502576367e+03; rpi =  3.4e-08; rdi =  1.0e-09; gap =  2.5e-04
+ 23: obj =   5.502057119e+03; rpi =  8.1e-09; rdi =  3.0e-10; gap =  7.7e-05
+ 24: obj =   5.501885996e+03; rpi =  9.4e-10; rdi =  1.2e-10; gap =  2.4e-05
+ 25: obj =   5.501852464e+03; rpi =  1.4e-10; rdi =  1.2e-11; gap =  3.0e-06
+ 26: obj =   5.501846549e+03; rpi =  1.4e-11; rdi =  1.2e-12; gap =  3.0e-07
+ 27: obj =   5.501845954e+03; rpi =  1.4e-12; rdi =  1.2e-13; gap =  3.0e-08
+ 28: obj =   5.501845895e+03; rpi =  1.5e-13; rdi =  1.2e-14; gap =  3.0e-09
+OPTIMAL SOLUTION FOUND
+Writing interior-point solution to `25fv47.txt'...
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_init\_iptcp---initialize interior-point solver control
+parameters}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_init_iptcp(glp_iptcp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_init_iptcp| initializes control parameters, which
+are used by the interior-point solver, with default values.
+
+Default values of the control parameters are stored in the structure
+\verb|glp_iptcp|, which the parameter \verb|parm| points to.
+
+\subsection{glp\_ipt\_status---determine solution status}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ipt_status(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ipt_status| reports the status of a solution
+found by the interior-point solver as follows:
+
+\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
+\verb|GLP_UNDEF| & interior-point solution is undefined. \\
+\verb|GLP_OPT|   & interior-point solution is optimal. \\
+\verb|GLP_INFEAS|& interior-point solution is infeasible. \\
+\verb|GLP_NOFEAS|& no feasible primal-dual solution exists.\\
+\end{tabular}
+
+\subsection{glp\_ipt\_obj\_val---retrieve objective value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_ipt_obj_val(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ipt_obj_val| returns value of the objective
+function for interior-point solution.
+
+\subsection{glp\_ipt\_row\_prim---retrieve row primal value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_ipt_row_prim(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ipt_row_prim| returns primal value of the
+auxiliary variable associated with \verb|i|-th row.
+
+\newpage
+
+\subsection{glp\_ipt\_row\_dual---retrieve row dual value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_ipt_row_dual(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ipt_row_dual| returns dual value (i.e. reduced
+cost) of the auxiliary variable associated with \verb|i|-th row.
+
+\subsection{glp\_ipt\_col\_prim---retrieve column primal value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_ipt_col_prim(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ipt_col_prim| returns primal value of the
+structural variable associated with \verb|j|-th column.
+
+\subsection{glp\_ipt\_col\_dual---retrieve column dual value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_ipt_col_dual(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ipt_col_dual| returns dual value (i.e. reduced
+cost) of the structural variable associated with \verb|j|-th column.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Mixed integer programming routines}
+
+\subsection{glp\_set\_col\_kind---set (change) column kind}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_col_kind(glp_prob *mip, int j, int kind);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_col_kind| sets (changes) the kind of
+\verb|j|-th column (structural variable) as specified by the parameter
+\verb|kind|:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_CV| & continuous variable; \\
+\verb|GLP_IV| & integer variable; \\
+\verb|GLP_BV| & binary variable. \\
+\end{tabular}
+
+%If a column is set to \verb|GLP_IV|, its bounds must be exact integer
+%numbers with no tolerance, such that the condition
+%\verb|bnd == floor(bnd)| would hold.
+
+Setting a column to \verb|GLP_BV| has the same effect as if it were
+set to \verb|GLP_IV|, its lower bound were set 0, and its upper bound
+were set to 1.
+
+\subsection{glp\_get\_col\_kind---retrieve column kind}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_col_kind(glp_prob *mip, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_kind| returns the kind of \verb|j|-th
+column (structural variable) as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_CV| & continuous variable; \\
+\verb|GLP_IV| & integer variable; \\
+\verb|GLP_BV| & binary variable. \\
+\end{tabular}
+
+\subsection{glp\_get\_num\_int---retrieve number of integer columns}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_num_int(glp_prob *mip);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_num_int| returns the number of columns
+(structural variables), which are marked as integer. Note that this
+number {\it does} include binary columns.
+
+\subsection{glp\_get\_num\_bin---retrieve number of binary columns}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_num_bin(glp_prob *mip);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_num_bin| returns the number of columns
+(structural variables), which are marked as integer and whose lower
+bound is zero and upper bound is one.
+
+\subsection{glp\_intopt---solve MIP problem with the branch-and-cut
+method}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_intopt(glp_prob *mip, const glp_iocp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_intopt| is a driver to the MIP solver based on
+the branch-and-cut method, which is a hybrid of branch-and-bound and
+cutting plane methods.
+
+If the presolver is disabled (see paragraph ``Control parameters''
+below), on entry to the routine \verb|glp_intopt| the problem object,
+which the parameter \verb|mip| points to, should contain optimal
+solution to LP relaxation (it can be obtained, for example, with the
+routine \verb|glp_simplex|). Otherwise, if the presolver is enabled, it
+is not necessary.
+
+The MIP solver has a set of control parameters. Values of the control
+parameters can be passed in the structure \verb|glp_iocp|, which the
+parameter \verb|parm| points to. For detailed description of this
+structure see paragraph ``Control parameters'' below. Before specifying
+some control parameters the application program should initialize the
+structure \verb|glp_iocp| by default values of all control parameters
+using the routine \verb|glp_init_iocp| (see the next subsection). This
+is needed for backward compatibility, because in the future there may
+appear new members in the structure \verb|glp_iocp|.
+
+The parameter \verb|parm| can be specified as \verb|NULL|, in which case
+the solver uses default settings.
+
+Note that the GLPK branch-and-cut solver is not perfect, so it is unable
+to solve hard or very large scale MIP instances for a reasonable time.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The MIP problem instance has been successfully solved. (This code
+does {\it not} necessarily mean that the solver has found optimal
+solution. It only means that the solution process was successful.) \\
+\verb|GLP_EBOUND| & Unable to start the search, because some
+double-bounded variables have incorrect bounds or some integer variables
+have non-integer (fractional) bounds.\\
+\verb|GLP_EROOT| & Unable to start the search, because optimal basis for
+initial LP relaxation is not provided. (This code may appear only if the
+presolver is disabled.)\\
+\verb|GLP_ENOPFS| & Unable to start the search, because LP relaxation
+of the MIP problem instance has no primal feasible solution. (This code
+may appear only if the presolver is enabled.)\\
+\verb|GLP_ENODFS| & Unable to start the search, because LP relaxation
+of the MIP problem instance has no dual feasible solution. In other
+word, this code means that if the LP relaxation has at least one primal
+feasible solution, its optimal solution is unbounded, so if the MIP
+problem has at least one integer feasible solution, its (integer)
+optimal solution is also unbounded. (This code may appear only if the
+presolver is enabled.)\\
+\verb|GLP_EFAIL| & The search was prematurely terminated due to the
+solver failure.\\
+\verb|GLP_EMIPGAP| & The search was prematurely terminated, because the
+relative mip gap tolerance has been reached.\\
+\verb|GLP_ETMLIM| & The search was prematurely terminated, because the
+time limit has been exceeded.\\
+\verb|GLP_ESTOP| & The search was prematurely terminated by application.
+(This code may appear only if the advanced solver interface is used.)\\
+\end{tabular}
+
+\subsubsection*{Built-in MIP presolver}
+
+The branch-and-cut solver has {\it built-in MIP presolver}. It is
+a subprogram that transforms the original MIP problem specified in the
+problem object to an equivalent MIP problem, which may be easier for
+solving with the branch-and-cut method than the original one. For
+example, the presolver can remove redundant constraints and variables,
+whose optimal values are known, perform bound and coefficient reduction,
+etc. Once the transformed MIP problem has been solved, the presolver
+transforms its solution back to corresponding solution of the original
+problem.
+
+Presolving is an optional feature of the routine \verb|glp_intopt|, and
+by default it is disabled. In order to enable the MIP presolver, the
+control parameter \verb|presolve| should be set to \verb|GLP_ON| (see
+paragraph ``Control parameters'' below).
+
+\subsubsection*{Advanced solver interface}
+
+The routine \verb|glp_intopt| allows the user to control the
+branch-and-cut search by passing to the solver a user-defined callback
+routine. For more details see Chapter ``Branch-and-Cut API Routines''.
+
+\subsubsection*{Terminal output}
+
+Solving a MIP problem may take a long time, so the solver reports some
+information about best known solutions, which is sent to the terminal.
+This information has the following format:
+
+\begin{verbatim}
++nnn: mip = xxx <rho> yyy gap (ppp; qqq)
+\end{verbatim}
+
+\noindent
+where: `\verb|nnn|' is the simplex iteration number; `\verb|xxx|' is a
+value of the objective function for the best known integer feasible
+solution (if no integer feasible solution has been found yet,
+`\verb|xxx|' is the text `\verb|not found yet|'); `\verb|rho|' is the
+string `\verb|>=|' (in case of minimization) or `\verb|<=|' (in case of
+maximization); `\verb|yyy|' is a global bound for exact integer optimum
+(i.e. the exact integer optimum is always in the range from `\verb|xxx|'
+to `\verb|yyy|'); `\verb|gap|' is the relative mip gap, in percents,
+computed as $gap=|xxx-yyy|/(|xxx|+{\tt DBL\_EPSILON})\cdot 100\%$ (if
+$gap$ is greater than $999.9\%$, it is not printed); `\verb|ppp|' is the
+number of subproblems in the active list, `\verb|qqq|' is the number of
+subproblems which have been already fathomed and therefore removed from
+the branch-and-bound search tree.
+
+\subsubsection{Control parameters}
+
+This paragraph describes all control parameters currently used in the
+MIP solver. Symbolic names of control parameters are names of
+corresponding members in the structure \verb|glp_iocp|.
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int msg\_lev} (default: {\tt GLP\_MSG\_ALL})}
+\\
+&Message level for terminal output:\\
+&\verb|GLP_MSG_OFF|---no output;\\
+&\verb|GLP_MSG_ERR|---error and warning messages only;\\
+&\verb|GLP_MSG_ON |---normal output;\\
+&\verb|GLP_MSG_ALL|---full output (including informational messages).
+\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int br\_tech} (default: {\tt GLP\_BR\_DTH})}
+\\
+&Branching technique option:\\
+&\verb|GLP_BR_FFV|---first fractional variable;\\
+&\verb|GLP_BR_LFV|---last fractional variable;\\
+&\verb|GLP_BR_MFV|---most fractional variable;\\
+&\verb|GLP_BR_DTH|---heuristic by Driebeck and Tomlin;\\
+&\verb|GLP_BR_PCH|---hybrid pseudocost heuristic.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int bt\_tech} (default: {\tt GLP\_BT\_BLB})}
+\\
+&Backtracking technique option:\\
+&\verb|GLP_BT_DFS|---depth first search;\\
+&\verb|GLP_BT_BFS|---breadth first search;\\
+&\verb|GLP_BT_BLB|---best local bound;\\
+&\verb|GLP_BT_BPH|---best projection heuristic.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int pp\_tech} (default: {\tt GLP\_PP\_ALL})}
+\\
+&Preprocessing technique option:\\
+&\verb|GLP_PP_NONE|---disable preprocessing;\\
+&\verb|GLP_PP_ROOT|---perform preprocessing only on the root level;\\
+&\verb|GLP_PP_ALL |---perform preprocessing on all levels.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int fp\_heur} (default: {\tt GLP\_OFF})}
+\\
+&Feasibility pump heuristic option:\\
+&\verb|GLP_ON |---enable applying the feasibility pump heuristic;\\
+&\verb|GLP_OFF|---disable applying the feasibility pump heuristic.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int gmi\_cuts} (default: {\tt GLP\_OFF})}\\
+&Gomory's mixed integer cut option:\\
+&\verb|GLP_ON |---enable generating Gomory's cuts;\\
+&\verb|GLP_OFF|---disable generating Gomory's cuts.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int mir\_cuts} (default: {\tt GLP\_OFF})}\\
+&Mixed integer rounding (MIR) cut option:\\
+&\verb|GLP_ON |---enable generating MIR cuts;\\
+&\verb|GLP_OFF|---disable generating MIR cuts.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int cov\_cuts} (default: {\tt GLP\_OFF})}\\
+&Mixed cover cut option:\\
+&\verb|GLP_ON |---enable generating mixed cover cuts;\\
+&\verb|GLP_OFF|---disable generating mixed cover cuts.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int clq\_cuts} (default: {\tt GLP\_OFF})}\\
+&Clique cut option:\\
+&\verb|GLP_ON |---enable generating clique cuts;\\
+&\verb|GLP_OFF|---disable generating clique cuts.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double tol\_int} (default: {\tt 1e-5})}\\
+&Absolute tolerance used to check if optimal solution to the current LP
+relaxation is integer feasible. (Do not change this parameter without
+detailed understanding its purpose.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double tol\_obj} (default: {\tt 1e-7})}\\
+&Relative tolerance used to check if the objective value in optimal
+solution to the current LP relaxation is not better than in the best
+known integer feasible solution. (Do not change this parameter without
+detailed understanding its purpose.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double mip\_gap} (default: {\tt 0.0})}\\
+&The relative mip gap tolerance. If the relative mip gap for currently
+known best integer feasible solution falls below this tolerance, the
+solver terminates the search. This allows obtainig suboptimal integer
+feasible solutions if solving the problem to optimality takes too long
+time.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int tm\_lim} (default: {\tt INT\_MAX})}\\
+&Searching time limit, in milliseconds.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int out\_frq} (default: {\tt 5000})}\\
+&Output frequency, in milliseconds. This parameter specifies how
+frequently the solver sends information about the solution process to
+the terminal.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int out\_dly} (default: {\tt 10000})}\\
+&Output delay, in milliseconds. This parameter specifies how long the
+solver should delay sending information about solution of the current
+LP relaxation with the simplex method to the terminal.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}
+{{\tt void (*cb\_func)(glp\_tree *tree, void *info)}
+(default: {\tt NULL})}\\
+&Entry point to the user-defined callback routine. \verb|NULL| means
+the advanced solver interface is not used. For more details see Chapter
+``Branch-and-Cut API Routines''.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt void *cb\_info} (default: {\tt NULL})}\\
+&Transit pointer passed to the routine \verb|cb_func| (see above).\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int cb\_size} (default: {\tt 0})}\\
+&The number of extra (up to 256) bytes allocated for each node of the
+branch-and-bound tree to store application-specific data. On creating
+a node these bytes are initialized by binary zeros.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int presolve} (default: {\tt GLP\_OFF})}\\
+&MIP presolver option:\\
+&\verb|GLP_ON |---enable using the MIP presolver;\\
+&\verb|GLP_OFF|---disable using the MIP presolver.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int binarize} (default: {\tt GLP\_OFF})}\\
+&Binarization option (used only if the presolver is enabled):\\
+&\verb|GLP_ON |---replace general integer variables by binary ones;\\
+&\verb|GLP_OFF|---do not use binarization.\\
+\end{tabular}
+
+\subsection{glp\_init\_iocp---initialize integer optimizer control
+parameters}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_init_iocp(glp_iocp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_init_iocp| initializes control parameters, which
+are used by the branch-and-cut solver, with default values.
+
+Default values of the control parameters are stored in a \verb|glp_iocp|
+structure, which the parameter \verb|parm| points to.
+
+\subsection{glp\_mip\_status---determine status of MIP solution}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_mip_status(glp_prob *mip);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_mip_status| reports the status of a MIP solution
+found by the MIP solver as follows:
+
+\smallskip
+
+\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
+\verb|GLP_UNDEF| & MIP solution is undefined. \\
+\verb|GLP_OPT|   & MIP solution is integer optimal. \\
+\verb|GLP_FEAS|  & MIP solution is integer feasible, however, its
+   optimality (or non-optimality) has not been proven, perhaps due to
+   premature termination of the search. \\
+\end{tabular}
+
+\begin{tabular}{@{}p{25mm}p{91.3mm}@{}}
+\verb|GLP_NOFEAS| & problem has no integer feasible solution (proven by
+   the solver). \\
+\end{tabular}
+
+\subsection{glp\_mip\_obj\_val---retrieve objective value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_mip_obj_val(glp_prob *mip);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_mip_obj_val| returns value of the objective
+function for MIP solution.
+
+\subsection{glp\_mip\_row\_val---retrieve row value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_mip_row_val(glp_prob *mip, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_mip_row_val| returns value of the auxiliary
+variable associated with \verb|i|-th row for MIP solution.
+
+\subsection{glp\_mip\_col\_val---retrieve column value}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_mip_col_val(glp_prob *mip, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_mip_col_val| returns value of the structural
+variable associated with \verb|j|-th column for MIP solution.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Additional routines}
+
+\subsection{lpx\_check\_kkt---check Karush-Kuhn-Tucker optimality
+conditions}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void lpx_check_kkt(glp_prob *lp, int scaled, LPXKKT *kkt);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|lpx_check_kkt| checks Karush-Kuhn-Tucker optimality
+conditions for basic solution. It is assumed that both primal and dual
+components of basic solution are valid.
+
+If the parameter \verb|scaled| is zero, the optimality conditions are
+checked for the original, unscaled LP problem. Otherwise, if the
+parameter \verb|scaled| is non-zero, the routine checks the conditions
+for an internally scaled LP problem.
+
+The parameter \verb|kkt| is a pointer to the structure \verb|LPXKKT|,
+to which the routine stores results of the check. Members of this
+structure are shown in the table below.
+
+\begin{table}[h]
+\begin{center}
+\begin{tabular}{@{}c|l|l@{}}
+Condition & Member & Comment \\
+\hline
+(KKT.PE) & \verb|pe_ae_max| &
+         Largest absolute error \\
+         & \verb|pe_ae_row| &
+         Number of row with largest absolute error \\
+         & \verb|pe_re_max| &
+         Largest relative error \\
+         & \verb|pe_re_row| &
+         Number of row with largest relative error \\
+         & \verb|pe_quality| &
+         Quality of primal solution \\
+\hline
+(KKT.PB) & \verb|pb_ae_max| &
+         Largest absolute error \\
+         & \verb|pb_ae_ind| &
+         Number of variable with largest absolute error \\
+         & \verb|pb_re_max| &
+         Largest relative error \\
+         & \verb|pb_re_ind| &
+         Number of variable with largest relative error \\
+         & \verb|pb_quality| &
+         Quality of primal feasibility \\
+\hline
+(KKT.DE) & \verb|de_ae_max| &
+         Largest absolute error \\
+         & \verb|de_ae_col| &
+         Number of column with largest absolute error \\
+         & \verb|de_re_max| &
+         Largest relative error \\
+         & \verb|de_re_col| &
+         Number of column with largest relative error \\
+         & \verb|de_quality| &
+         Quality of dual solution \\
+\hline
+(KKT.DB) & \verb|db_ae_max| &
+         Largest absolute error \\
+         & \verb|db_ae_ind| &
+         Number of variable with largest absolute error \\
+         & \verb|db_re_max| &
+         Largest relative error \\
+         & \verb|db_re_ind| &
+         Number of variable with largest relative error \\
+         & \verb|db_quality| &
+         Quality of dual feasibility \\
+\end{tabular}
+\end{center}
+\end{table}
+
+The routine performs all computations using only components of the
+given LP problem and the current basic solution.
+
+\subsubsection*{Background}
+
+The first condition checked by the routine is:
+$$x_R - A x_S = 0, \eqno{\rm (KKT.PE)}$$
+where $x_R$ is the subvector of auxiliary variables (rows), $x_S$ is the
+subvector of structural variables (columns), $A$ is the constraint
+matrix. This condition expresses the requirement that all primal
+variables must satisfy to the system of equality constraints of the
+original LP problem. In case of exact arithmetic this condition would be
+satisfied for any basic solution; however, in case of inexact
+(floating-point) arithmetic, this condition shows how accurate the
+primal basic solution is, that depends on accuracy of a representation
+of the basis matrix used by the simplex method routines.
+
+The second condition checked by the routine is:
+$$l_k \leq x_k \leq u_k {\rm \ \ \ for\ all}\ k=1,\dots,m+n,
+\eqno{\rm (KKT.PB)}$$
+where $x_k$ is auxiliary ($1\leq k\leq m$) or structural
+($m+1\leq k\leq m+n$) variable, $l_k$ and $u_k$ are, respectively,
+lower and upper bounds of the variable $x_k$ (including cases of
+infinite bounds). This condition expresses the requirement that all
+primal variables must satisfy to bound constraints of the original LP
+problem. Since in case of basic solution all non-basic variables are
+placed on their bounds, actually the condition (KKT.PB) needs to be
+checked for basic variables only. If the primal basic solution has
+sufficient accuracy, this condition shows primal feasibility of the
+solution.
+
+The third condition checked by the routine is:
+$${\rm grad}\;Z = c = (\tilde{A})^T \pi + d,$$
+where $Z$ is the objective function, $c$ is the vector of objective
+coefficients, $(\tilde{A})^T$ is a matrix transposed to the expanded
+constraint matrix $\tilde{A} = (I|-A)$, $\pi$ is a vector of Lagrange
+multipliers that correspond to equality constraints of the original LP
+problem, $d$ is a vector of Lagrange multipliers that correspond to
+bound constraints for all (auxiliary and structural) variables of the
+original LP problem. Geometrically the third condition expresses the
+requirement that the gradient of the objective function must belong to
+the orthogonal complement of a linear subspace defined by the equality
+and active bound constraints, i.e. that the gradient must be a linear
+combination of normals to the constraint planes, where Lagrange
+multipliers $\pi$ and $d$ are coefficients of that linear combination.
+
+To eliminate the vector $\pi$ the third condition can be rewritten as:
+$$
+\left(\begin{array}{@{}c@{}}I \\ -A^T\end{array}\right) \pi =
+\left(\begin{array}{@{}c@{}}d_R \\ d_S\end{array}\right) +
+\left(\begin{array}{@{}c@{}}c_R \\ c_S\end{array}\right),
+$$
+or, equivalently:
+$$
+\begin{array}{r@{}c@{}c}
+\pi + d_R&\ =\ &c_R, \\
+-A^T\pi + d_S&\ =\ &c_S. \\
+\end{array}
+$$
+Then substituting the vector $\pi$ from the first equation into the
+second one we have:
+$$A^T (d_R - c_R) + (d_S - c_S) = 0, \eqno{\rm (KKT.DE)}$$
+where $d_R$ is the subvector of reduced costs of auxiliary variables
+(rows), $d_S$ is the subvector of reduced costs of structural variables
+(columns), $c_R$ and $c_S$ are subvectors of objective coefficients at,
+respectively, auxiliary and structural variables, $A^T$ is a matrix
+transposed to the constraint matrix of the original LP problem. In case
+of exact arithmetic this condition would be satisfied for any basic
+solution; however, in case of inexact (floating-point) arithmetic, this
+condition shows how accurate the dual basic solution is, that depends on
+accuracy of a representation of the basis matrix used by the simplex
+method routines.
+
+The last, fourth condition checked by the routine is (KKT.DB):
+
+\medskip
+
+\begin{tabular}{r@{}c@{}ll}
+&$\ d_k\ $& $=0,$&if $x_k$ is basic or free non-basic variable \\
+$0\leq$&$\ d_k\ $&$<+\infty$&if $x_k$ is non-basic on its lower
+(minimization) \\
+&&&or upper (maximization) bound \\
+$-\infty<$&$\ d_k\ $&$\leq 0$&if $x_k$ is non-basic on its upper
+(minimization) \\
+&&&or lower (maximization) bound \\
+$-\infty<$&$\ d_k\ $&$<+\infty$&if $x_k$ is non-basic fixed variable \\
+\end{tabular}
+
+\medskip
+
+\noindent
+for all $k=1,\dots,m+n$, where $d_k$ is a reduced cost (Lagrange
+multiplier) of auxiliary ($1\leq k\leq m$) or structural
+($m+1\leq k\leq m+n$) variable $x_k$. Geometrically this condition
+expresses the requirement that constraints of the original problem must
+"hold" the point preventing its movement along the anti-gradient (in
+case of minimization) or the gradient (in case of maximization) of the
+objective function. Since in case of basic solution reduced costs of
+all basic variables are placed on their (zero) bounds, actually the
+condition (KKT.DB) needs to be checked for non-basic variables only.
+If the dual basic solution has sufficient accuracy, this condition shows
+dual feasibility of the solution.
+
+Should note that the complete set of Karush-Kuhn-Tucker optimality
+conditions also includes the fifth, so called complementary slackness
+condition, which expresses the requirement that at least either a primal
+variable $x_k$ or its dual counterpart $d_k$ must be on its bound for
+all $k=1,\dots,m+n$. However, being always satisfied by definition for
+any basic solution that condition is not checked by the routine.
+
+To check the first condition (KKT.PE) the routine computes a vector of
+residuals:
+$$g = x_R - A x_S,$$
+determines component of this vector that correspond to largest absolute
+and relative errors:
+
+\medskip
+
+\hspace{30mm}
+\verb|pe_ae_max| $\displaystyle{= \max_{1\leq i\leq m}|g_i|}$,
+
+\medskip
+
+\hspace{30mm}
+\verb|pe_re_max| $\displaystyle{= \max_{1\leq i\leq m}
+\frac{|g_i|}{1+|(x_R)_i|}}$,
+
+\medskip
+
+\noindent
+and stores these quantities and corresponding row indices to the
+structure \verb|LPXKKT|.
+
+To check the second condition (KKT.PB) the routine computes a vector
+of residuals:
+$$
+h_k = \left\{
+\begin{array}{ll}
+0,         & {\rm if}\ l_k \leq x_k \leq u_k \\
+x_k - l_k, & {\rm if}\ x_k < l_k \\
+x_k - u_k, & {\rm if}\ x_k > u_k \\
+\end{array}
+\right.
+$$
+for all $k=1,\dots,m+n$, determines components of this vector that
+correspond to largest absolute and relative errors:
+
+\medskip
+
+\hspace{30mm}
+\verb|pb_ae_max| $\displaystyle{= \max_{1\leq k \leq m+n}|h_k|}$,
+
+\medskip
+
+\hspace{30mm}
+\verb|pb_re_max| $\displaystyle{= \max_{1\leq k \leq m+n}
+\frac{|h_k|}{1+|x_k|}}$,
+
+\medskip
+
+\noindent
+and stores these quantities and corresponding variable indices to the
+structure \verb|LPXKKT|.
+
+To check the third condition (KKT.DE) the routine computes a vector of
+residuals:
+$$u = A^T (d_R - c_R) + (d_S - c_S),$$
+determines components of this vector that correspond to largest
+absolute and relative errors:
+
+\medskip
+
+\hspace{30mm}
+\verb|de_ae_max| $\displaystyle{= \max_{1\leq j\leq n}|u_j|}$,
+
+\medskip
+
+\hspace{30mm}
+\verb|de_re_max| $\displaystyle{= \max_{1\leq j\leq n}
+\frac{|u_j|}{1+|(d_S)_j - (c_S)_j|}}$,
+
+\medskip
+
+\noindent
+and stores these quantities and corresponding column indices to the
+structure \verb|LPXKKT|.
+
+To check the fourth condition (KKT.DB) the routine computes a vector
+of residuals:
+
+$$
+v_k = \left\{
+\begin{array}{ll}
+0,         & {\rm if}\ d_k\ {\rm has\ correct\ sign} \\
+d_k,       & {\rm if}\ d_k\ {\rm has\ wrong\ sign} \\
+\end{array}
+\right.
+$$
+for all $k=1,\dots,m+n$, determines components of this vector that
+correspond to largest absolute and relative errors:
+
+\medskip
+
+\hspace{30mm}
+\verb|db_ae_max| $\displaystyle{= \max_{1\leq k\leq m+n}|v_k|}$,
+
+\medskip
+
+\hspace{30mm}
+\verb|db_re_max| $\displaystyle{= \max_{1\leq k\leq m+n}
+\frac{|v_k|}{1+|d_k - c_k|}}$,
+
+\medskip
+
+\noindent
+and stores these quantities and corresponding variable indices to the
+structure \verb|LPXKKT|.
+
+Using the relative errors for all the four conditions listed above the
+routine
+\verb|lpx_check_kkt| also estimates a "quality" of the basic solution
+from the standpoint of these conditions and stores corresponding
+quality indicators to the structure \verb|LPXKKT|:
+
+\verb|pe_quality|---quality of primal solution;
+
+\verb|pb_quality|---quality of primal feasibility;
+
+\verb|de_quality|---quality of dual solution;
+
+\verb|db_quality|---quality of dual feasibility.
+
+Each of these indicators is assigned to one of the following four
+values:
+
+\verb|'H'| means high quality,
+
+\verb|'M'| means medium quality,
+
+\verb|'L'| means low quality, or
+
+\verb|'?'| means wrong or infeasible solution.
+
+If all the indicators show high or medium quality (for an internally
+scaled LP problem, i.e. when the parameter \verb|scaled| in a call to
+the routine \verb|lpx_check_kkt| is non-zero), the user can be sure that
+the obtained basic solution is quite accurate.
+
+If some of the indicators show low quality, the solution can still be
+considered as relevant, though an additional analysis is needed
+depending on which indicator shows low quality.
+
+If the indicator \verb|pe_quality| is assigned to \verb|'?'|, the
+primal solution is wrong. If the indicator \verb|de_quality| is assigned
+to \verb|'?'|, the dual solution is wrong.
+
+If the indicator \verb|db_quality| is assigned to \verb|'?'| while
+other indicators show a good quality, this means that the current
+basic solution being primal feasible is not dual feasible. Similarly,
+if the indicator \verb|pb_quality| is assigned to \verb|'?'| while
+other indicators are not, this means that the current basic solution
+being dual feasible is not primal feasible.
+
+%* eof *%
Index: deps/glpk/doc/glpk03.tex
===================================================================
--- deps/glpk/doc/glpk03.tex	(revision 9)
+++ deps/glpk/doc/glpk03.tex	(revision 9)
@@ -0,0 +1,1577 @@
+%* glpk03.tex *%
+
+\chapter{Utility API routines}
+
+\section{Problem data reading/writing routines}
+
+\subsection{glp\_read\_mps---read problem data in MPS format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_mps(glp_prob *lp, int fmt, const void *parm,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_mps| reads problem data in MPS format from a
+text file. (The MPS format is described in Appendix \ref{champs}, page
+\pageref{champs}.)
+
+The parameter \verb|fmt| specifies the MPS format version as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_MPS_DECK| & fixed (ancient) MPS format; \\
+\verb|GLP_MPS_FILE| & free (modern) MPS format. \\
+\end{tabular}
+
+The parameter \verb|parm| is reserved for use in the future and must be
+specified as \verb|NULL|.
+
+The character string \verb|fname| specifies a name of the text file to
+be read in. (If the file name ends with suffix `\verb|.gz|', the file is
+assumed to be compressed, in which case the routine \verb|glp_read_mps|
+decompresses it ``on the fly''.)
+
+Note that before reading data the current content of the problem object
+is completely erased with the routine \verb|glp_erase_prob|.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_read_mps|
+returns zero. Otherwise, it prints an error message and returns
+non-zero.
+
+\subsection{glp\_write\_mps---write problem data in MPS format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_mps(glp_prob *lp, int fmt, const void *parm,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_mps| writes problem data in MPS format to a
+text file. (The MPS format is described in Appendix \ref{champs}, page
+\pageref{champs}.)
+
+The parameter \verb|fmt| specifies the MPS format version as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_MPS_DECK| & fixed (ancient) MPS format; \\
+\verb|GLP_MPS_FILE| & free (modern) MPS format. \\
+\end{tabular}
+
+The parameter \verb|parm| is reserved for use in the future and must be
+specified as \verb|NULL|.
+
+The character string \verb|fname| specifies a name of the text file to
+be written out. (If the file name ends with suffix `\verb|.gz|', the
+file is assumed to be compressed, in which case the routine
+\verb|glp_write_mps| performs automatic compression on writing it.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_write_mps|
+returns zero. Otherwise, it prints an error message and returns
+non-zero.
+
+\subsection{glp\_read\_lp---read problem data in CPLEX LP format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_lp(glp_prob *lp, const void *parm,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_lp| reads problem data in CPLEX LP format
+from a text file. (The CPLEX LP format is described in Appendix
+\ref{chacplex}, page \pageref{chacplex}.)
+
+The parameter \verb|parm| is reserved for use in the future and must be
+specified as \verb|NULL|.
+
+The character string \verb|fname| specifies a name of the text file to
+be read in. (If the file name ends with suffix `\verb|.gz|', the file is
+assumed to be compressed, in which case the routine \verb|glp_read_lp|
+decompresses it ``on the fly''.)
+
+Note that before reading data the current content of the problem object
+is completely erased with the routine \verb|glp_erase_prob|.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_read_lp| returns
+zero. Otherwise, it prints an error message and returns non-zero.
+
+\subsection{glp\_write\_lp---write problem data in CPLEX LP format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_lp(glp_prob *lp, const void *parm,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_lp| writes problem data in CPLEX LP format
+to a text file. (The CPLEX LP format is described in Appendix
+\ref{chacplex}, page \pageref{chacplex}.)
+
+The parameter \verb|parm| is reserved for use in the future and must be
+specified as \verb|NULL|.
+
+The character string \verb|fname| specifies a name of the text file to
+be written out. (If the file name ends with suffix `\verb|.gz|', the
+file is assumed to be compressed, in which case the routine
+\verb|glp_write_lp| performs automatic compression on writing it.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_write_lp|
+returns zero. Otherwise, it prints an error message and returns
+non-zero.
+
+\subsection{glp\_read\_prob---read problem data in GLPK format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_prob(glp_prob *P, int flags, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_prob| reads problem data in the GLPK LP/MIP
+format from a text file. (For description of the GLPK LP/MIP format see
+below.)
+
+The parameter \verb|flags| is reserved for use in the future and should
+be specified as zero.
+
+The character string \verb|fname| specifies a name of the text file to
+be read in. (If the file name ends with suffix `\verb|.gz|', the file
+is assumed to be compressed, in which case the routine
+\verb|glp_read_prob| decompresses it ``on the fly''.)
+
+Note that before reading data the current content of the problem object
+is completely erased with the routine \verb|glp_erase_prob|.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_read_prob|
+returns zero. Otherwise, it prints an error message and returns
+non-zero.
+
+\subsubsection*{GLPK LP/MIP format}
+
+The GLPK LP/MIP format is a DIMACS-like format.\footnote{The DIMACS
+formats were developed by the Center for Discrete Mathematics and
+Theoretical Computer Science (DIMACS) to facilitate exchange of problem
+data. For details see: {\tt <http://dimacs.rutgers.edu/Challenges/>}. }
+The file in this format is a plain ASCII text file containing lines of
+several types described below. A line is terminated with the end-of-line
+character. Fields in each line are separated by at least one blank
+space. Each line begins with a one-character designator to identify the
+line type.
+
+The first line of the data file must be the problem line (except
+optional comment lines, which may precede the problem line). The last
+line of the data file must be the end line. Other lines may follow in
+arbitrary order, however, duplicate lines are not allowed.
+
+\paragraph{Comment lines.} Comment lines give human-readable
+information about the data file and are ignored by GLPK routines.
+Comment lines can appear anywhere in the data file. Each comment line
+begins with the lower-case character \verb|c|.
+
+\begin{verbatim}
+   c This is an example of comment line
+\end{verbatim}
+
+\paragraph{Problem line.} There must be exactly one problem line in the
+data file. This line must appear before any other lines except comment
+lines and has the following format:
+
+\begin{verbatim}
+   p CLASS DIR ROWS COLS NONZ
+\end{verbatim}
+
+The lower-case letter \verb|p| specifies that this is the problem line.
+
+The \verb|CLASS| field defines the problem class and can contain either
+the keyword \verb|lp| (that means linear programming problem) or
+\verb|mip| (that means mixed integer programming problem).
+
+The \verb|DIR| field defines the optimization direction (that is, the
+objective function sense) and can contain either the keyword \verb|min|
+(that means minimization) or \verb|max| (that means maximization).
+
+The \verb|ROWS|, \verb|COLS|, and \verb|NONZ| fields contain
+non-negative integer values specifying, respectively, the number of
+rows (constraints), columns (variables), and non-zero constraint
+coefficients in the problem instance. Note that \verb|NONZ| value does
+not account objective coefficients.
+
+\paragraph{Row descriptors.} There must be at most one row descriptor
+line in the data file for each row (constraint). This line has one of
+the following formats:
+
+\begin{verbatim}
+   i ROW f
+   i ROW l RHS
+   i ROW u RHS
+   i ROW d RHS1 RHS2
+   i ROW s RHS
+\end{verbatim}
+
+The lower-case letter \verb|i| specifies that this is the row
+descriptor line.
+
+The \verb|ROW| field specifies the row ordinal number, an integer
+between 1 and $m$, where $m$ is the number of rows in the problem
+instance.
+
+The next lower-case letter specifies the row type as follows:
+
+\verb|f| --- free (unbounded) row: $-\infty<\sum a_jx_j<+\infty$;
+
+\verb|l| --- inequality constraint of `$\geq$' type:
+$\sum a_jx_j\geq b$;
+
+\verb|u| --- inequality constraint of `$\leq$' type:
+$\sum a_jx_j\leq b$;
+
+\verb|d| --- double-sided inequality constraint:
+$b_1\leq\sum a_jx_j\leq b_2$;
+
+\verb|s| --- equality constraint: $\sum a_jx_j=b$.
+
+The \verb|RHS| field contains a floaing-point value specifying the
+row right-hand side. The \verb|RHS1| and \verb|RHS2| fields contain
+floating-point values specifying, respectively, the lower and upper
+right-hand sides for the double-sided row.
+
+If for some row its descriptor line does not appear in the data file,
+by default that row is assumed to be an equality constraint with zero
+right-hand side.
+
+\paragraph{Column descriptors.} There must be at most one column
+descriptor line in the data file for each column (variable). This line
+has one of the following formats depending on the problem class
+specified in the problem line:
+
+\bigskip
+
+\begin{tabular}{@{}l@{\hspace*{40pt}}l}
+LP class & MIP class \\
+\hline
+\verb|j COL f|           & \verb|j COL KIND f|           \\
+\verb|j COL l BND|       & \verb|j COL KIND l BND|       \\
+\verb|j COL u BND|       & \verb|j COL KIND u BND|       \\
+\verb|j COL d BND1 BND2| & \verb|j COL KIND d BND1 BND2| \\
+\verb|j COL s BND|       & \verb|j COL KIND s BND|       \\
+\end{tabular}
+
+\bigskip
+
+The lower-case letter \verb|j| specifies that this is the column
+descriptor line.
+
+The \verb|COL| field specifies the column ordinal number, an integer
+between 1 and $n$, where $n$ is the number of columns in the problem
+instance.
+
+The \verb|KIND| field is used only for MIP problems and specifies the
+column kind as follows:
+
+\verb|c| --- continuous column;
+
+\verb|i| --- integer column;
+
+\verb|b| --- binary column (in this case all remaining fields must be
+omitted).
+
+The next lower-case letter specifies the column type as follows:
+
+\verb|f| --- free (unbounded) column: $-\infty<x<+\infty$;
+
+\verb|l| --- column with lower bound: $x\geq l$;
+
+\verb|u| --- column with upper bound: $x\leq u$;
+
+\verb|d| --- double-bounded column: $l\leq x\leq u$;
+
+\verb|s| --- fixed column: $x=s$.
+
+The \verb|BND| field contains a floating-point value that specifies the
+column bound. The \verb|BND1| and \verb|BND2| fields contain
+floating-point values specifying, respectively, the lower and upper
+bounds for the double-bounded column.
+
+If for some column its descriptor line does not appear in the file, by
+default that column is assumed to be non-negative (in case of LP class)
+or binary (in case of MIP class).
+
+\paragraph{Coefficient descriptors.} There must be exactly one
+coefficient descriptor line in the data file for each non-zero
+objective or constraint coefficient. This line has the following format:
+
+\begin{verbatim}
+   a ROW COL VAL
+\end{verbatim}
+
+The lower-case letter \verb|a| specifies that this is the coefficient
+descriptor line.
+
+For objective coefficients the \verb|ROW| field must contain 0. For
+constraint coefficients the \verb|ROW| field specifies the row ordinal
+number, an integer between 1 and $m$, where $m$ is the number of rows
+in the problem instance.
+
+The \verb|COL| field specifies the column ordinal number, an integer
+between 1 and $n$, where $n$ is the number of columns in the problem
+instance.
+
+If both the \verb|ROW| and \verb|COL| fields contain 0, the line
+specifies the constant term (``shift'') of the objective function
+rather than objective coefficient.
+
+The \verb|VAL| field contains a floating-point coefficient value (it is
+allowed to specify zero value in this field).
+
+The number of constraint coefficient descriptor lines must be exactly
+the same as specified in the field \verb|NONZ| of the problem line.
+
+\paragraph{Symbolic name descriptors.} There must be at most one
+symbolic name descriptor line for the problem instance, objective
+function, each row (constraint), and each column (variable). This line
+has one of the following formats:
+
+\begin{verbatim}
+   n p NAME
+   n z NAME
+   n i ROW NAME
+   n j COL NAME
+\end{verbatim}
+
+The lower-case letter \verb|n| specifies that this is the symbolic name
+descriptor line.
+
+The next lower-case letter specifies which object should be assigned a
+symbolic name:
+
+\verb|p| --- problem instance;
+
+\verb|z| --- objective function;
+
+\verb|i| --- row (constraint);
+
+\verb|j| --- column (variable).
+
+The \verb|ROW| field specifies the row ordinal number, an integer
+between 1 and $m$, where $m$ is the number of rows in the problem
+instance.
+
+The \verb|COL| field specifies the column ordinal number, an integer
+between 1 and $n$, where $n$ is the number of columns in the problem
+instance.
+
+The \verb|NAME| field contains the symbolic name, a sequence from 1 to
+255 arbitrary graphic ASCII characters, assigned to corresponding
+object.
+
+\paragraph{End line.} There must be exactly one end line in the data
+file. This line must appear last in the file and has the following
+format:
+
+\begin{verbatim}
+   e
+\end{verbatim}
+
+The lower-case letter \verb|e| specifies that this is the end line.
+Anything that follows the end line is ignored by GLPK routines.
+
+\subsubsection*{Example of data file in GLPK LP/MIP format}
+
+The following example of a data file in GLPK LP/MIP format specifies
+the same LP problem as in Subsection ``Example of MPS file''.
+
+\begin{center}
+\footnotesize\tt
+\begin{tabular}{l@{\hspace*{50pt}}}
+p lp min 8 7 48   \\
+n p PLAN          \\
+n z VALUE         \\
+i 1 f             \\
+n i 1 VALUE       \\
+i 2 s 2000        \\
+n i 2 YIELD       \\
+i 3 u 60          \\
+n i 3 FE          \\
+i 4 u 100         \\
+n i 4 CU          \\
+i 5 u 40          \\
+n i 5 MN          \\
+i 6 u 30          \\
+n i 6 MG          \\
+i 7 l 1500        \\
+n i 7 AL          \\
+i 8 d 250 300     \\
+n i 8 SI          \\
+j 1 d 0 200       \\
+n j 1 BIN1        \\
+j 2 d 0 2500      \\
+n j 2 BIN2        \\
+j 3 d 400 800     \\
+n j 3 BIN3        \\
+j 4 d 100 700     \\
+n j 4 BIN4        \\
+j 5 d 0 1500      \\
+n j 5 BIN5        \\
+n j 6 ALUM        \\
+n j 7 SILICON     \\
+a 0 1 0.03        \\
+a 0 2 0.08        \\
+a 0 3 0.17        \\
+a 0 4 0.12        \\
+a 0 5 0.15        \\
+a 0 6 0.21        \\
+a 0 7 0.38        \\
+a 1 1 0.03        \\
+a 1 2 0.08        \\
+a 1 3 0.17        \\
+a 1 4 0.12        \\
+a 1 5 0.15        \\
+a 1 6 0.21        \\
+\end{tabular}
+\begin{tabular}{|@{\hspace*{80pt}}l}
+a 1 7 0.38        \\
+a 2 1 1           \\
+a 2 2 1           \\
+a 2 3 1           \\
+a 2 4 1           \\
+a 2 5 1           \\
+a 2 6 1           \\
+a 2 7 1           \\
+a 3 1 0.15        \\
+a 3 2 0.04        \\
+a 3 3 0.02        \\
+a 3 4 0.04        \\
+a 3 5 0.02        \\
+a 3 6 0.01        \\
+a 3 7 0.03        \\
+a 4 1 0.03        \\
+a 4 2 0.05        \\
+a 4 3 0.08        \\
+a 4 4 0.02        \\
+a 4 5 0.06        \\
+a 4 6 0.01        \\
+a 5 1 0.02        \\
+a 5 2 0.04        \\
+a 5 3 0.01        \\
+a 5 4 0.02        \\
+a 5 5 0.02        \\
+a 6 1 0.02        \\
+a 6 2 0.03        \\
+a 6 5 0.01        \\
+a 7 1 0.7         \\
+a 7 2 0.75        \\
+a 7 3 0.8         \\
+a 7 4 0.75        \\
+a 7 5 0.8         \\
+a 7 6 0.97        \\
+a 8 1 0.02        \\
+a 8 2 0.06        \\
+a 8 3 0.08        \\
+a 8 4 0.12        \\
+a 8 5 0.02        \\
+a 8 6 0.01        \\
+a 8 7 0.97        \\
+e o f             \\
+\\
+\end{tabular}
+\end{center}
+
+\newpage
+
+\subsection{glp\_write\_prob---write problem data in GLPK format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_prob(glp_prob *P, int flags, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_prob| writes problem data in the GLPK
+LP/MIP format to a text file. (For description of the GLPK LP/MIP
+format see Subsection ``Read problem data in GLPK format''.)
+
+The parameter \verb|flags| is reserved for use in the future and should
+be specified as zero.
+
+The character string \verb|fname| specifies a name of the text file to
+be written out. (If the file name ends with suffix `\verb|.gz|', the
+file is assumed to be compressed, in which case the routine
+\verb|glp_write_prob| performs automatic compression on writing it.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_read_prob|
+returns zero. Otherwise, it prints an error message and returns
+non-zero.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Routines for processing MathProg models}
+
+\subsection{Introduction}
+
+GLPK supports the {\it GNU MathProg modeling language}.\footnote{The
+GNU MathProg modeling language is a subset of the AMPL language. For
+its detailed description see the document ``Modeling Language GNU
+MathProg: Language Reference'' included in the GLPK distribution.}
+As a rule, models written in MathProg are solved with the GLPK LP/MIP
+stand-alone solver \verb|glpsol| (see Appendix D) and do not need any
+programming with API routines. However, for various reasons the user
+may need to process MathProg models directly in his/her application
+program, in which case he/she may use API routines described in this
+section. These routines provide an interface to the {\it MathProg
+translator}, a component of GLPK, which translates MathProg models into
+an internal code and then interprets (executes) this code.
+
+The processing of a model written in GNU MathProg includes several
+steps, which should be performed in the following order:
+
+\begin{enumerate}
+\item{\it Allocating the workspace.}
+The translator allocates the workspace, an internal data structure used
+on all subsequent steps.
+\item{\it Reading model section.} The translator reads model section
+and, optionally, data section from a specified text file and translates
+them into the internal code. If necessary, on this step data section
+may be ignored.
+\item{\it Reading data section(s).} The translator reads one or more
+data sections from specified text file(s) and translates them into the
+internal code.
+\item{\it Generating the model.} The translator executes the internal
+code to evaluate the content of the model objects such as sets,
+parameters, variables, constraints, and objectives. On this step the
+execution is suspended at the solve statement.
+\item {\it Building the problem object.} The translator obtains all
+necessary information from the workspace and builds the standard
+problem object (that is, the program object of type \verb|glp_prob|).
+\item{\it Solving the problem.} On this step the problem object built
+on the previous step is passed to a solver, which solves the problem
+instance and stores its solution back to the problem object.
+\item{\it Postsolving the model.} The translator copies the solution
+from the problem object to the workspace and then executes the internal
+code from the solve statement to the end of the model. (If model has
+no solve statement, the translator does nothing on this step.)
+\item{\it Freeing the workspace.} The translator frees all the memory
+allocated to the workspace.
+\end{enumerate}
+
+Note that the MathProg translator performs no error correction, so if
+any of steps 2 to 7 fails (due to errors in the model), the application
+program should terminate processing and go to step 8.
+
+\subsubsection*{Example 1}
+
+In this example the program reads model and data sections from input
+file \verb|egypt.mod|\footnote{This is an example model included in
+the GLPK distribution.} and writes the model to output file
+\verb|egypt.mps| in free MPS format (see Appendix B). No solution is
+performed.
+
+\begin{small}
+\begin{verbatim}
+/* mplsamp1.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *lp;
+      glp_tran *tran;
+      int ret;
+      lp = glp_create_prob();
+      tran = glp_mpl_alloc_wksp();
+      ret = glp_mpl_read_model(tran, "egypt.mod", 0);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on translating model\n");
+         goto skip;
+      }
+      ret = glp_mpl_generate(tran, NULL);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on generating model\n");
+         goto skip;
+      }
+      glp_mpl_build_prob(tran, lp);
+      ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, "egypt.mps");
+      if (ret != 0)
+         fprintf(stderr, "Error on writing MPS file\n");
+skip: glp_mpl_free_wksp(tran);
+      glp_delete_prob(lp);
+      return 0;
+}
+
+/* eof */
+\end{verbatim}
+\end{small}
+
+\subsubsection*{Example 2}
+
+In this example the program reads model section from file
+\verb|sudoku.mod|\footnote{This is an example model which is included
+in the GLPK distribution along with alternative data file
+{\tt sudoku.dat}.} ignoring data section in this file, reads alternative
+data section from file \verb|sudoku.dat|, solves the problem instance
+and passes the solution found back to the model.
+
+\begin{small}
+\begin{verbatim}
+/* mplsamp2.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *mip;
+      glp_tran *tran;
+      int ret;
+      mip = glp_create_prob();
+      tran = glp_mpl_alloc_wksp();
+      ret = glp_mpl_read_model(tran, "sudoku.mod", 1);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on translating model\n");
+         goto skip;
+      }
+      ret = glp_mpl_read_data(tran, "sudoku.dat");
+      if (ret != 0)
+      {  fprintf(stderr, "Error on translating data\n");
+         goto skip;
+      }
+      ret = glp_mpl_generate(tran, NULL);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on generating model\n");
+         goto skip;
+      }
+      glp_mpl_build_prob(tran, mip);
+      glp_simplex(mip, NULL);
+      glp_intopt(mip, NULL);
+      ret = glp_mpl_postsolve(tran, mip, GLP_MIP);
+      if (ret != 0)
+         fprintf(stderr, "Error on postsolving model\n");
+skip: glp_mpl_free_wksp(tran);
+      glp_delete_prob(mip);
+      return 0;
+}
+
+/* eof */
+\end{verbatim}
+\end{small}
+
+\subsection{glp\_mpl\_alloc\_wksp---allocate the translator workspace}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+glp_tran *glp_mpl_alloc_wksp(void);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mpl_alloc_wksp| allocates the MathProg translator
+work\-space. (Note that multiple instances of the workspace may be
+allocated, if necessary.)
+
+\subsubsection*{Returns}
+
+The routine returns a pointer to the workspace, which should be used in
+all subsequent operations.
+
+\subsection{glp\_mpl\_read\_model---read and translate model section}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_mpl_read_model(glp_tran *tran, const char *fname,
+      int skip);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mpl_read_model| reads model section and,
+optionally, data section, which may follow the model section, from a
+text file, whose name is the character string \verb|fname|, performs
+translation of model statements and data blocks, and stores all the
+information in the workspace.
+
+The parameter \verb|skip| is a flag. If the input file contains the
+data section and this flag is non-zero, the data section is not read as
+if there were no data section and a warning message is printed. This
+allows reading data section(s) from other file(s).
+
+\subsubsection*{Returns}
+
+If the operation is successful, the routine returns zero. Otherwise
+the routine prints an error message and returns non-zero.
+
+\subsection{glp\_mpl\_read\_data---read and translate data section}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_mpl_read_data(glp_tran *tran, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mpl_read_data| reads data section from a text
+file, whose name is the character string \verb|fname|, performs
+translation of data blocks, and stores the data read in the translator
+workspace. If necessary, this routine may be called more than once.
+
+\subsubsection*{Returns}
+
+If the operation is successful, the routine returns zero. Otherwise
+the routine prints an error message and returns non-zero.
+
+\subsection{glp\_mpl\_generate---generate the model}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_mpl_generate(glp_tran *tran, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mpl_generate| generates the model using its
+description stored in the translator workspace. This operation means
+generating all variables, constraints, and objectives, executing check
+and display statements, which precede the solve statement (if it is
+presented).
+
+The character string \verb|fname| specifies the name of an output text
+file, to which output produced by display statements should be written.
+If \verb|fname| is \verb|NULL|, the output is sent to the terminal.
+
+\subsubsection*{Returns}
+
+If the operation is successful, the routine returns zero. Otherwise
+the routine prints an error message and returns non-zero.
+
+\subsection{glp\_mpl\_build\_prob---build problem instance from the
+model}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mpl_build_prob| obtains all necessary information
+from the translator workspace and stores it in the specified problem
+object \verb|prob|. Note that before building the current content of
+the problem object is erased with the routine \verb|glp_erase_prob|.
+
+\subsection{glp\_mpl\_postsolve---postsolve the model}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob,
+      int sol);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mpl_postsolve| copies the solution from the
+specified problem object \verb|prob| to the translator workspace and
+then executes all the remaining model statements, which follow the
+solve statement.
+
+The parameter \verb|sol| specifies which solution should be copied
+from the problem object to the workspace as follows:
+
+\begin{tabular}{@{}ll}
+\verb|GLP_SOL| & basic solution; \\
+\verb|GLP_IPT| & interior-point solution; \\
+\verb|GLP_MIP| & mixed integer solution. \\
+\end{tabular}
+
+\subsubsection*{Returns}
+
+If the operation is successful, the routine returns zero. Otherwise
+the routine prints an error message and returns non-zero.
+
+\subsection{glp\_mpl\_free\_wksp---free the translator workspace}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_mpl_free_wksp(glp_tran *tran);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mpl_free_wksp| frees all the memory allocated to
+the translator workspace. It also frees all other resources, which are
+still used by the translator.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Problem solution reading/writing routines}
+
+\subsection{glp\_print\_sol---write basic solution in printable format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_print_sol(glp_prob *lp, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_print_sol writes| the current basic solution of
+an LP problem, which is specified by the pointer \verb|lp|, to a text
+file, whose name is the character string \verb|fname|, in printable
+format.
+
+Information reported by the routine \verb|glp_print_sol| is intended
+mainly for visual analysis.
+
+\subsubsection*{Returns}
+
+If no errors occurred, the routine returns zero. Otherwise the routine
+prints an error message and returns non-zero.
+
+\subsection{glp\_read\_sol---read basic solution from text file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_sol(glp_prob *lp, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_sol| reads basic solution from a text file
+whose name is specified by the parameter \verb|fname| into the problem
+object.
+
+For the file format see description of the routine \verb|glp_write_sol|.
+
+\subsubsection*{Returns}
+
+On success the routine returns zero, otherwise non-zero.
+
+\newpage
+
+\subsection{glp\_write\_sol---write basic solution to text file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_sol(glp_prob *lp, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_sol| writes the current basic solution to a
+text file whose name is specified by the parameter \verb|fname|. This
+file can be read back with the routine \verb|glp_read_sol|.
+
+\subsubsection*{Returns}
+
+On success the routine returns zero, otherwise non-zero.
+
+\subsubsection*{File format}
+
+The file created by the routine \verb|glp_write_sol| is a plain text
+file, which contains the following information:
+
+\begin{verbatim}
+   m n
+   p_stat d_stat obj_val
+   r_stat[1] r_prim[1] r_dual[1]
+   . . .
+   r_stat[m] r_prim[m] r_dual[m]
+   c_stat[1] c_prim[1] c_dual[1]
+   . . .
+   c_stat[n] c_prim[n] c_dual[n]
+\end{verbatim}
+
+\noindent
+where:
+
+\noindent
+$m$ is the number of rows (auxiliary variables);
+
+\noindent
+$n$ is the number of columns (structural variables);
+
+\noindent
+\verb|p_stat| is the primal status of the basic solution
+(\verb|GLP_UNDEF| = 1, \verb|GLP_FEAS| = 2, \verb|GLP_INFEAS| = 3, or
+\verb|GLP_NOFEAS| = 4);
+
+\noindent
+\verb|d_stat| is the dual status of the basic solution
+(\verb|GLP_UNDEF| = 1, \verb|GLP_FEAS| = 2, \verb|GLP_INFEAS| = 3, or
+\verb|GLP_NOFEAS| = 4);
+
+\noindent
+\verb|obj_val| is the objective value;
+
+\noindent
+\verb|r_stat[i]|, $i=1,\dots,m$, is the status of $i$-th row
+(\verb|GLP_BS| = 1, \verb|GLP_NL| = 2, \verb|GLP_NU| = 3,
+\verb|GLP_NF| = 4, or \verb|GLP_NS| = 5);
+
+\noindent
+\verb|r_prim[i]|, $i=1,\dots,m$, is the primal value of $i$-th row;
+
+\noindent
+\verb|r_dual[i]|, $i=1,\dots,m$, is the dual value of $i$-th row;
+
+\noindent
+\verb|c_stat[j]|, $j=1,\dots,n$, is the status of $j$-th column
+(\verb|GLP_BS| = 1, \verb|GLP_NL| = 2, \verb|GLP_NU| = 3,
+\verb|GLP_NF| = 4, or \verb|GLP_NS| = 5);
+
+\noindent
+\verb|c_prim[j]|, $j=1,\dots,n$, is the primal value of $j$-th column;
+
+\noindent
+\verb|c_dual[j]|, $j=1,\dots,n$, is the dual value of $j$-th column.
+
+\subsection{glp\_print\_ipt---write interior-point solution in
+printable format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_print_ipt(glp_prob *lp, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_print_ipt| writes the current interior point
+solution  of an LP problem, which the parameter \verb|lp| points to, to
+a text file, whose name is the character string \verb|fname|, in
+printable format.
+
+Information reported by the routine \verb|glp_print_ipt| is intended
+mainly for visual analysis.
+
+\subsubsection*{Returns}
+
+If no errors occurred, the routine returns zero. Otherwise the routine
+prints an error message and returns non-zero.
+
+\subsection{glp\_read\_ipt---read interior-point solution from text
+file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_ipt(glp_prob *lp, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_ipt| reads interior-point solution from a
+text file whose name is specified by the parameter \verb|fname| into the
+problem object.
+
+For the file format see description of the routine \verb|glp_write_ipt|.
+
+\subsubsection*{Returns}
+
+On success the routine returns zero, otherwise non-zero.
+
+\subsection{glp\_write\_ipt---write interior-point solution to text
+file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_ipt(glp_prob *lp, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_ipt| writes the current interior-point
+solution to a text file whose name is specified by the parameter
+\verb|fname|. This file can be read back with the routine
+\verb|glp_read_ipt|.
+
+\subsubsection*{Returns}
+
+On success the routine returns zero, otherwise non-zero.
+
+\subsubsection*{File format}
+
+The file created by the routine \verb|glp_write_ipt| is a plain text
+file, which contains the following information:
+
+\begin{verbatim}
+   m n
+   stat obj_val
+   r_prim[1] r_dual[1]
+   . . .
+   r_prim[m] r_dual[m]
+   c_prim[1] c_dual[1]
+   . . .
+   c_prim[n] c_dual[n]
+\end{verbatim}
+
+\noindent
+where:
+
+\noindent
+$m$ is the number of rows (auxiliary variables);
+
+\noindent
+$n$ is the number of columns (structural variables);
+
+\noindent
+\verb|stat| is the solution status (\verb|GLP_UNDEF| = 1 or
+\verb|GLP_OPT| = 5);
+
+\noindent
+\verb|obj_val| is the objective value;
+
+\noindent
+\verb|r_prim[i]|, $i=1,\dots,m$, is the primal value of $i$-th row;
+
+\noindent
+\verb|r_dual[i]|, $i=1,\dots,m$, is the dual value of $i$-th row;
+
+\noindent
+\verb|c_prim[j]|, $j=1,\dots,n$, is the primal value of $j$-th column;
+
+\noindent
+\verb|c_dual[j]|, $j=1,\dots,n$, is the dual value of $j$-th column.
+
+\subsection{glp\_print\_mip---write MIP solution in printable format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_print_mip(glp_prob *lp, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_print_mip| writes a best known integer solution
+of a MIP problem, which is specified by the pointer \verb|lp|, to a text
+file, whose name is the character string \verb|fname|, in printable
+format.
+
+Information reported by the routine \verb|glp_print_mip| is intended
+mainly for visual analysis.
+
+\subsubsection*{Returns}
+
+If no errors occurred, the routine returns zero. Otherwise the routine
+prints an error message and returns non-zero.
+
+\newpage
+
+\subsection{glp\_read\_mip---read MIP solution from text file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_mip(glp_prob *mip, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_mip| reads MIP solution from a text file
+whose name is specified by the parameter \verb|fname| into the problem
+object.
+
+For the file format see description of the routine \verb|glp_write_mip|.
+
+\subsubsection*{Returns}
+
+On success the routine returns zero, otherwise non-zero.
+
+\subsection{glp\_write\_mip---write MIP solution to text file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_mip(glp_prob *mip, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_mip| writes the current MIP solution to a
+text file whose name is specified by the parameter \verb|fname|. This
+file can be read back with the routine \verb|glp_read_mip|.
+
+\subsubsection*{Returns}
+
+On success the routine returns zero, otherwise non-zero.
+
+\subsubsection*{File format}
+
+The file created by the routine \verb|glp_write_sol| is a plain text
+file, which contains the following information:
+
+\begin{verbatim}
+   m n
+   stat obj_val
+   r_val[1]
+   . . .
+   r_val[m]
+   c_val[1]
+   . . .
+   c_val[n]
+\end{verbatim}
+
+\noindent
+where:
+
+\noindent
+$m$ is the number of rows (auxiliary variables);
+
+\noindent
+$n$ is the number of columns (structural variables);
+
+\noindent
+\verb|stat| is the solution status (\verb|GLP_UNDEF| = 1,
+\verb|GLP_FEAS| = 2, \verb|GLP_NOFEAS| = 4, or \verb|GLP_OPT| = 5);
+
+\noindent
+\verb|obj_val| is the objective value;
+
+\noindent
+\verb|r_val[i]|, $i=1,\dots,m$, is the value of $i$-th row;
+
+\noindent
+\verb|c_val[j]|, $j=1,\dots,n$, is the value of $j$-th column.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Post-optimal analysis routines}
+
+\subsection{glp\_print\_ranges---print sensitivity analysis report}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_print_ranges(glp_prob *P, int len, const int list[],
+      int flags, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_print_ranges| performs sensitivity analysis of
+current optimal basic solution and writes the analysis report in
+human-readable format to a text file, whose name is the character
+string {\it fname}. (Detailed description of the report structure is
+given below.)
+
+The parameter {\it len} specifies the length of the row/column list.
+
+The array {\it list} specifies ordinal number of rows and columns to be
+analyzed. The ordinal numbers should be passed in locations
+{\it list}[1], {\it list}[2], \dots, {\it list}[{\it len}]. Ordinal
+numbers from 1 to $m$ refer to rows, and ordinal numbers from $m+1$ to
+$m+n$ refer to columns, where $m$ and $n$ are, resp., the total number
+of rows and columns in the problem object. Rows and columns appear in
+the analysis report in the same order as they follow in the array list.
+
+It is allowed to specify $len=0$, in which case the array {\it list} is
+not used (so it can be specified as \verb|NULL|), and the routine
+performs analysis for all rows and columns of the problem object.
+
+The parameter {\it flags} is reserved for use in the future and must be
+specified as zero.
+
+On entry to the routine \verb|glp_print_ranges| the current basic
+solution must be optimal and the basis factorization must exist.
+The application program can check that with the routine
+\verb|glp_bf_exists|, and if the factorization does
+not exist, compute it with the routine \verb|glp_factorize|. Note that
+if the LP preprocessor is not used, on normal exit from the simplex
+solver routine \verb|glp_simplex| the basis factorization always exists.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_print_ranges|
+returns zero. Otherwise, it prints an error message and returns
+non-zero.
+
+\subsubsection*{Analysis report example}
+
+An example of the sensitivity analysis report is shown on the next two
+pages. This example corresponds to the example of LP problem described
+in Subsection ``Example of MPS file''.
+
+\subsubsection*{Structure of the analysis report}
+
+For each row and column specified in the array {\it list} the routine
+prints two lines containing generic information and analysis
+information, which depends on the status of corresponding row or column.
+
+Note that analysis of a row is analysis of its auxiliary variable,
+which is equal to the row linear form $\sum a_jx_j$, and analysis of
+a column is analysis of corresponding structural variable. Therefore,
+formally, on performing the sensitivity analysis there is no difference
+between rows and columns.
+
+\bigskip
+
+\noindent
+{\it Generic information}
+
+\medskip
+
+\noindent
+{\tt No.} is the row or column ordinal number in the problem object.
+Rows are numbered from 1 to $m$, and columns are numbered from 1 to $n$,
+where $m$ and $n$ are, resp., the total number of rows and columns in
+the problem object.
+
+\medskip
+
+\noindent
+{\tt Row name} is the symbolic name assigned to the row. If the row has
+no name assigned, this field contains blanks.
+
+\medskip
+
+\noindent
+{\tt Column name} is the symbolic name assigned to the column. If the
+column has no name assigned, this field contains blanks.
+
+\medskip
+
+\noindent
+{\tt St} is the status of the row or column in the optimal solution:
+
+{\tt BS} --- non-active constraint (row), basic column;
+
+{\tt NL} --- inequality constraint having its lower right-hand side
+active (row), non-basic column having its lower bound active;
+
+{\tt NU} --- inequality constraint having its upper right-hand side
+active (row), non-basic column having its upper bound active;
+
+{\tt NS} --- active equality constraint (row), non-basic fixed column.
+
+{\tt NF} --- active free row, non-basic free (unbounded) column. (This
+case means that the optimal solution is dual degenerate.)
+
+\medskip
+
+\noindent
+{\tt Activity} is the (primal) value of the auxiliary variable (row) or
+structural variable (column) in the optimal solution.
+
+\medskip
+
+\noindent
+{\tt Slack} is the (primal) value of the row slack variable.
+
+\medskip
+
+\noindent
+{\tt Obj coef} is the objective coefficient of the column (structural
+variable).
+
+\begin{landscape}
+\begin{scriptsize}
+\begin{verbatim}
+GLPK 4.42 - SENSITIVITY ANALYSIS REPORT                                                                         Page   1
+
+Problem:    PLAN
+Objective:  VALUE = 296.2166065 (MINimum)
+
+   No. Row name     St      Activity         Slack   Lower bound       Activity      Obj coef  Obj value at Limiting
+                                          Marginal   Upper bound          range         range   break point variable
+------ ------------ -- ------------- ------------- -------------  ------------- ------------- ------------- ------------
+     1 VALUE        BS     296.21661    -296.21661          -Inf      299.25255      -1.00000        .      MN
+                                            .               +Inf      296.21661          +Inf          +Inf
+
+     2 YIELD        NS    2000.00000        .         2000.00000     1995.06864          -Inf     296.28365 BIN3
+                                           -.01360    2000.00000     2014.03479          +Inf     296.02579 CU
+
+     3 FE           NU      60.00000        .               -Inf       55.89016          -Inf     306.77162 BIN4
+                                          -2.56823      60.00000       62.69978       2.56823     289.28294 BIN3
+
+     4 CU           BS      83.96751      16.03249          -Inf       93.88467       -.30613     270.51157 MN
+                                            .          100.00000       79.98213        .21474     314.24798 BIN5
+
+     5 MN           NU      40.00000        .               -Inf       34.42336          -Inf     299.25255 BIN4
+                                           -.54440      40.00000       41.68691        .54440     295.29825 BIN3
+
+     6 MG           BS      19.96029      10.03971          -Inf       24.74427      -1.79618     260.36433 BIN1
+                                            .           30.00000        9.40292        .28757     301.95652 MN
+
+     7 AL           NL    1500.00000        .         1500.00000     1485.78425       -.25199     292.63444 CU
+                                            .25199          +Inf     1504.92126          +Inf     297.45669 BIN3
+
+     8 SI           NL     250.00000      50.00000     250.00000      235.32871       -.48520     289.09812 CU
+                                            .48520     300.00000      255.06073          +Inf     298.67206 BIN3
+\end{verbatim}
+\end{scriptsize}
+\end{landscape}
+
+\begin{landscape}
+\begin{scriptsize}
+\begin{verbatim}
+GLPK 4.42 - SENSITIVITY ANALYSIS REPORT                                                                         Page   2
+
+Problem:    PLAN
+Objective:  VALUE = 296.2166065 (MINimum)
+
+   No. Column name  St      Activity      Obj coef   Lower bound       Activity      Obj coef  Obj value at Limiting
+                                          Marginal   Upper bound          range         range   break point variable
+------ ------------ -- ------------- ------------- -------------  ------------- ------------- ------------- ------------
+     1 BIN1         NL        .             .03000        .           -28.82475       -.22362     288.90594 BIN4
+                                            .25362     200.00000       33.88040          +Inf     304.80951 BIN4
+
+     2 BIN2         BS     665.34296        .08000        .           802.22222        .01722     254.44822 BIN1
+                                            .         2500.00000      313.43066        .08863     301.95652 MN
+
+     3 BIN3         BS     490.25271        .17000     400.00000      788.61314        .15982     291.22807 MN
+                                            .          800.00000     -347.42857        .17948     300.86548 BIN5
+
+     4 BIN4         BS     424.18773        .12000     100.00000      710.52632        .10899     291.54745 MN
+                                            .          700.00000     -256.15524        .14651     307.46010 BIN1
+
+     5 BIN5         NL        .             .15000        .          -201.78739        .13544     293.27940 BIN3
+                                            .01456    1500.00000       58.79586          +Inf     297.07244 BIN3
+
+     6 ALUM         BS     299.63899        .21000        .           358.26772        .18885     289.87879 AL
+                                            .               +Inf      112.40876        .22622     301.07527 MN
+
+     7 SILICON      BS     120.57762        .38000        .           124.27093        .14828     268.27586 BIN5
+                                            .               +Inf       85.54745        .46667     306.66667 MN
+
+End of report
+\end{verbatim}
+\end{scriptsize}
+\end{landscape}
+
+\noindent
+{\tt Marginal} is the reduced cost (dual activity) of the auxiliary
+variable (row) or structural variable (column).
+
+\medskip
+
+\noindent
+{\tt Lower bound} is the lower right-hand side (row) or lower bound
+(column). If the row or column has no lower bound, this field contains
+{\tt -Inf}.
+
+\medskip
+
+\noindent
+{\tt Upper bound} is the upper right-hand side (row) or upper bound
+(column). If the row or column has no upper bound, this field contains
+{\tt +Inf}.
+
+\bigskip
+
+\noindent
+{\it Sensitivity analysis of active bounds}
+
+\medskip
+
+\noindent
+The sensitivity analysis of active bounds is performed only for rows,
+which are active constraints, and only for non-basic columns, because
+inactive constraints and basic columns have no active bounds.
+
+For every auxiliary (row) or structural (column) non-basic variable the
+routine starts changing its active bound in both direction. The first
+of the two lines in the report corresponds to decreasing, and the
+second line corresponds to increasing of the active bound. Since the
+variable being analyzed is non-basic, its activity, which is equal to
+its active bound, also starts changing. This changing leads to changing
+of basic (auxiliary and structural) variables, which depend on the
+non-basic variable. The current basis remains primal feasible and
+therefore optimal while values of all basic variables are primal
+feasible, i.e. are within their bounds. Therefore, if some basic
+variable called the {\it limiting variable} reaches its (lower or
+upper) bound first, before any other basic variables, it thereby limits
+further changing of the non-basic variable, because otherwise the
+current basis would become primal infeasible. The point, at which this
+happens, is called the {\it break point}. Note that there are two break
+points: the lower break point, which corresponds to decreasing of the
+non-basic variable, and the upper break point, which corresponds to
+increasing of the non-basic variable.
+
+In the analysis report values of the non-basic variable (i.e. of its
+active bound) being analyzed at both lower and upper break points are
+printed in the field `{\tt Activity range}'. Corresponding values of
+the objective function are printed in the field `{\tt Obj value at
+break point}', and symbolic names of corresponding limiting basic
+variables are printed in the field `{\tt Limiting variable}'.
+If the active bound can decrease or/and increase unlimitedly, the field
+`{\tt Activity range}' contains {\tt -Inf} or/and {\tt +Inf}, resp.
+
+For example (see the example report above), row SI is a double-sided
+constraint, which is active on its lower bound (right-hand side), and
+its activity in the optimal solution being equal to the lower bound is
+250. The activity range for this row is $[235.32871,255.06073]$. This
+means that the basis remains optimal while the lower bound is
+increasing up to 255.06073, and further increasing is limited by
+(structural) variable BIN3. If the lower bound reaches this upper break
+point, the objective value becomes equal to 298.67206.
+
+Note that if the basis does not change, the objective function depends
+on the non-basic variable linearly, and the per-unit change of the
+objective function is the reduced cost (marginal value) of the
+non-basic variable.
+
+\bigskip
+
+\noindent
+{\it Sensitivity analysis of objective coefficients at non-basic
+variables}
+
+\medskip
+
+\noindent
+The sensitivity analysis of the objective coefficient at a non-basic
+variable is quite simple, because in this case change in the objective
+coefficient leads to equivalent change in the reduced cost (marginal
+value).
+
+For every auxiliary (row) or structural (column) non-basic variable the
+routine starts changing its objective coefficient in both direction.
+(Note that auxiliary variables are not included in the objective
+function and therefore always have zero objective coefficients.) The
+first of the two lines in the report corresponds to decreasing, and the
+second line corresponds to increasing of the objective coefficient.
+This changing leads to changing of the reduced cost of the non-basic
+variable to be analyzed and does affect reduced costs of all other
+non-basic variables. The current basis remains dual feasible and
+therefore optimal while the reduced cost keeps its sign. Therefore, if
+the reduced cost reaches zero, it limits further changing of the
+objective coefficient (if only the non-basic variable is non-fixed).
+
+In the analysis report minimal and maximal values of the objective
+coefficient, on which the basis remains optimal, are printed in the
+field `\verb|Obj coef range|'. If the objective coefficient can
+decrease or/and increase unlimitedly, this field contains {\tt -Inf}
+or/and {\tt +Inf}, resp.
+
+For example (see the example report above), column BIN5 is non-basic
+having its lower bound active. Its objective coefficient is 0.15, and
+reduced cost in the optimal solution 0.01456. The column lower bound
+remains active while the column reduced cost remains non-negative,
+thus, minimal value of the objective coefficient, on which the current
+basis still remains optimal, is $0.15-0.01456=0.13644$, that is
+indicated in the field `\verb|Obj coef range|'.
+
+\bigskip
+
+\noindent
+{\it Sensitivity analysis of objective coefficients at basic variables}
+
+\medskip
+
+\noindent
+To perform sensitivity analysis for every auxiliary (row) or structural
+(column) variable the routine starts changing its objective coefficient
+in both direction. (Note that auxiliary variables are not included in
+the objective function and therefore always have zero objective
+coefficients.) The first of the two lines in the report corresponds to
+decreasing, and the second line corresponds to increasing of the
+objective coefficient. This changing leads to changing of reduced costs
+of non-basic variables. The current basis remains dual feasible and
+therefore optimal while reduced costs of all non-basic variables
+(except fixed variables) keep their signs. Therefore, if the reduced
+cost of some non-basic non-fixed variable called the {\it limiting
+variable} reaches zero first, before reduced cost of any other
+non-basic non-fixed variable, it thereby limits further changing of the
+objective coefficient, because otherwise the current basis would become
+dual infeasible (non-optimal). The point, at which this happens, is
+called the {\it break point}. Note that there are two break points: the
+lower break point, which corresponds to decreasing of the objective
+coefficient, and the upper break point, which corresponds to increasing
+of the objective coefficient. Let the objective coefficient reach its
+limit value and continue changing a bit further in the same direction
+that makes the current basis dual infeasible (non-optimal). Then the
+reduced cost of the non-basic limiting variable becomes ``a bit'' dual
+infeasible that forces the limiting variable to enter the basis
+replacing there some basic variable, which leaves the basis to keep its
+primal feasibility. It should be understood that if we change the
+current basis in this way exactly at the break point, both the current
+and adjacent bases will be optimal with the same objective value,
+because at the break point the limiting variable has zero reduced cost.
+On the other hand, in the adjacent basis the value of the limiting
+variable changes, because there it becomes basic, that leads to
+changing of the value of the basic variable being analyzed. Note that
+on determining the adjacent basis the bounds of the analyzed basic
+variable are ignored as if it were a free (unbounded) variable, so it
+cannot leave the current basis.
+
+In the analysis report lower and upper limits of the objective
+coefficient at the basic variable being analyzed, when the basis
+remains optimal, are printed in the field `{\tt Obj coef range}'.
+Corresponding values of the objective function at both lower and upper
+break points are printed in the field `{\tt Obj value at break point}',
+symbolic names of corresponding non-basic limiting variables are
+printed in the field `{\tt Limiting variable}', and values of the basic
+variable, which it would take on in the adjacent bases (as was
+explained above) are printed in the field `{\tt Activity range}'.
+If the objective coefficient can increase or/and decrease unlimitedly,
+the field `{\tt Obj coef range}' contains {\tt -Inf} and/or {\tt +Inf},
+resp. It also may happen that no dual feasible adjacent basis exists
+(i.e. on entering the basis the limiting variable can increase or
+decrease unlimitedly), in which case the field `{\tt Activity range}'
+contains {\tt -Inf} and/or {\tt +Inf}.
+
+\newpage
+
+For example (see the example report above), structural variable
+(column) BIN3 is basic, its optimal value is 490.25271, and its
+objective coefficient is 0.17. The objective coefficient range for this
+column is $[0.15982,0.17948]$. This means that the basis remains
+optimal while the objective coefficient is decreasing down to 0.15982,
+and further decreasing is limited by (auxiliary) variable MN. If we
+make the objective coefficient a bit less than 0.15982, the limiting
+variable MN will enter the basis, and in that adjacent basis the
+structural variable BIN3 will take on new optimal value 788.61314. At
+the lower break point, where the objective coefficient is exactly
+0.15982, the objective function takes on the value 291.22807 in both
+the current and adjacent bases.
+
+Note that if the basis does not change, the objective function depends
+on the objective coefficient at the basic variable linearly, and the
+per-unit change of the objective function is the value of the basic
+variable.
+
+%* eof *%
Index: deps/glpk/doc/glpk04.tex
===================================================================
--- deps/glpk/doc/glpk04.tex	(revision 9)
+++ deps/glpk/doc/glpk04.tex	(revision 9)
@@ -0,0 +1,1411 @@
+%* glpk04.tex *%
+
+\chapter{Advanced API Routines}
+
+\section{Background}
+\label{basbgd}
+
+Using vector and matrix notations LP problem (1.1)---(1.3) (see Section
+\ref{seclp}, page \pageref{seclp}) can be stated as follows:
+
+\medskip
+
+\noindent
+\hspace{.5in} minimize (or maximize)
+$$z=c^Tx_S+c_0\eqno(3.1)$$
+\hspace{.5in} subject to linear constraints
+$$x_R=Ax_S\eqno(3.2)$$
+\hspace{.5in} and bounds of variables
+$$
+\begin{array}{l@{\ }c@{\ }l@{\ }c@{\ }l}
+l_R&\leq&x_R&\leq&u_R\\
+l_S&\leq&x_S&\leq&u_S\\
+\end{array}\eqno(3.3)
+$$
+where:
+
+\noindent
+$x_R=(x_1,\dots,x_m)$ is the vector of auxiliary variables;
+
+\noindent
+$x_S=(x_{m+1},\dots,x_{m+n})$ is the vector of structural
+variables;
+
+\noindent
+$z$ is the objective function;
+
+\noindent
+$c=(c_1,\dots,c_n)$ is the vector of objective coefficients;
+
+\noindent
+$c_0$ is the constant term (``shift'') of the objective function;
+
+\noindent
+$A=(a_{11},\dots,a_{mn})$ is the constraint matrix;
+
+\noindent
+$l_R=(l_1,\dots,l_m)$ is the vector of lower bounds of auxiliary
+variables;
+
+\noindent
+$u_R=(u_1,\dots,u_m)$ is the vector of upper bounds of auxiliary
+variables;
+
+\noindent
+$l_S=(l_{m+1},\dots,l_{m+n})$ is the vector of lower bounds of
+structural variables;
+
+\noindent
+$u_S=(u_{m+1},\dots,u_{m+n})$ is the vector of upper bounds of
+structural variables.
+
+\medskip
+
+From the simplex method's standpoint there is no difference between
+auxiliary and structural variables. This allows combining all these
+variables into one vector that leads to the following problem statement:
+
+\medskip
+
+\noindent
+\hspace{.5in} minimize (or maximize)
+$$z=(0\ |\ c)^Tx+c_0\eqno(3.4)$$
+\hspace{.5in} subject to linear constraints
+$$(I\ |-\!A)x=0\eqno(3.5)$$
+\hspace{.5in} and bounds of variables
+$$l\leq x\leq u\eqno(3.6)$$
+where:
+
+\noindent
+$x=(x_R\ |\ x_S)$ is the $(m+n)$-vector of (all) variables;
+
+\noindent
+$(0\ |\ c)$ is the $(m+n)$-vector of objective
+coefficients;\footnote{Subvector 0 corresponds to objective coefficients
+at auxiliary variables.}
+
+\noindent
+$(I\ |-\!A)$ is the {\it augmented} constraint
+$m\times(m+n)$-matrix;\footnote{Note that due to auxiliary variables
+matrix $(I\ |-\!A)$ contains the unity submatrix and therefore has full
+rank. This means, in particular, that the system (3.5) has no linearly
+dependent constraints.}
+
+\noindent
+$l=(l_R\ |\ l_S)$ is the $(m+n)$-vector of lower bounds of (all)
+variables;
+
+\noindent
+$u=(u_R\ |\ u_S)$ is the $(m+n)$-vector of upper bounds of (all)
+variables.
+
+\medskip
+
+By definition an {\it LP basic solution} geometrically is a point in
+the space of all variables, which is the intersection of planes
+corresponding to active constraints\footnote{A constraint is called
+{\it active} if in a given point it is satisfied as equality, otherwise
+it is called {\it inactive}.}. The space of all variables has the
+dimension $m+n$, therefore, to define some basic solution we have to
+define $m+n$ active constraints. Note that $m$ constraints (3.5) being
+linearly independent equalities are always active, so remaining $n$
+active constraints can be chosen only from bound constraints (3.6).
+
+A variable is called {\it non-basic}, if its (lower or upper) bound is
+active, otherwise it is called {\it basic}. Since, as was said above,
+exactly $n$ bound constraints must be active, in any basic solution
+there are always $n$ non-basic variables and $m$ basic variables.
+(Note that a free variable also can be non-basic. Although such
+variable has no bounds, we can think it as the difference between two
+non-negative variables, which both are non-basic in this case.)
+
+Now consider how to determine numeric values of all variables for a
+given basic solution.
+
+Let $\Pi$ be an appropriate permutation matrix of the order $(m+n)$.
+Then we can write:
+$$\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=
+\Pi\left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)=\Pi x,
+\eqno(3.7)$$
+where $x_B$ is the vector of basic variables, $x_N$ is the vector of
+non-basic variables, $x=(x_R\ |\ x_S)$ is the vector of all variables
+in the original order. In this case the system of linear constraints
+(3.5) can be rewritten as follows:
+$$(I\ |-\!A)\Pi^T\Pi x=0\ \ \ \Rightarrow\ \ \ (B\ |\ N)
+\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=0,\eqno(3.8)$$
+where
+$$(B\ |\ N)=(I\ |-\!A)\Pi^T.\eqno(3.9)$$
+Matrix $B$ is a square non-singular $m\times m$-matrix, which is
+composed from columns of the augmented constraint matrix corresponding
+to basic variables. It is called the {\it basis matrix} or simply the
+{\it basis}. Matrix $N$ is a rectangular $m\times n$-matrix, which is
+composed from columns of the augmented constraint matrix corresponding
+to non-basic variables.
+
+From (3.8) it follows that:
+$$Bx_B+Nx_N=0,\eqno(3.10)$$
+therefore,
+$$x_B=-B^{-1}Nx_N.\eqno(3.11)$$
+Thus, the formula (3.11) shows how to determine numeric values of basic
+variables $x_B$ assuming that non-basic variables $x_N$ are fixed on
+their active bounds.
+
+The $m\times n$-matrix
+$$\Xi=-B^{-1}N,\eqno(3.12)$$
+which appears in (3.11), is called the {\it simplex
+tableau}.\footnote{This definition corresponds to the GLPK
+implementation.} It shows how basic variables depend on non-basic
+variables:
+$$x_B=\Xi x_N.\eqno(3.13)$$
+
+The system (3.13) is equivalent to the system (3.5) in the sense that
+they both define the same set of points in the space of (primal)
+variables, which satisfy to these systems. If, moreover, values of all
+basic variables satisfy to their bound constraints (3.3), the
+corresponding basic solution is called {\it (primal) feasible},
+otherwise {\it (primal) infeasible}. It is understood that any (primal)
+feasible basic solution satisfy to all constraints (3.2) and (3.3).
+
+The LP theory says that if LP has optimal solution, it has (at least
+one) basic feasible solution, which corresponds to the optimum. And the
+most natural way to determine whether a given basic solution is optimal
+or not is to use the Karush---Kuhn---Tucker optimality conditions.
+
+\def\arraystretch{1.5}
+
+For the problem statement (3.4)---(3.6) the optimality conditions are
+the following:\footnote{These conditions can be appiled to any solution,
+not only to a basic solution.}
+$$(I\ |-\!A)x=0\eqno(3.14)$$
+$$(I\ |-\!A)^T\pi+\lambda_l+\lambda_u=\nabla z=(0\ |\ c)^T\eqno(3.15)$$
+$$l\leq x\leq u\eqno(3.16)$$
+$$\lambda_l\geq 0,\ \ \lambda_u\leq 0\ \ \mbox{(minimization)}
+\eqno(3.17)$$
+$$\lambda_l\leq 0,\ \ \lambda_u\geq 0\ \ \mbox{(maximization)}
+\eqno(3.18)$$
+$$(\lambda_l)_k(x_k-l_k)=0,\ \ (\lambda_u)_k(x_k-u_k)=0,\ \ k=1,2,\dots,
+m+n\eqno(3.19)$$
+where:
+$\pi=(\pi_1,\pi_2,\dots,\pi_m)$ is a $m$-vector of Lagrange
+multipliers for equality constraints (3.5);
+$\lambda_l=[(\lambda_l)_1,(\lambda_l)_2,\dots,(\lambda_l)_n]$ is a
+$n$-vector of Lagrange multipliers for lower bound constraints (3.6);
+$\lambda_u=[(\lambda_u)_1,(\lambda_u)_2,\dots,(\lambda_u)_n]$ is a
+$n$-vector of Lagrange multipliers for upper bound constraints (3.6).
+
+Condition (3.14) is the {\it primal} (original) system of equality
+constraints (3.5).
+
+Condition (3.15) is the {\it dual} system of equality constraints.
+It requires the gradient of the objective function to be a linear
+combination of normals to the planes defined by constraints of the
+original problem.
+
+Condition (3.16) is the primal (original) system of bound constraints
+(3.6).
+
+Condition (3.17) (or (3.18) in case of maximization) is the dual system
+of bound constraints.
+
+Condition (3.19) is the {\it complementary slackness condition}. It
+requires, for each original (auxiliary or structural) variable $x_k$,
+that either its (lower or upper) bound must be active, or zero bound of
+the corresponding Lagrange multiplier ($(\lambda_l)_k$ or
+$(\lambda_u)_k$) must be active.
+
+In GLPK two multipliers $(\lambda_l)_k$ and $(\lambda_u)_k$ for each
+primal (original) variable $x_k$, $k=1,2,\dots,m+n$, are combined into
+one multiplier:
+$$\lambda_k=(\lambda_l)_k+(\lambda_u)_k,\eqno(3.20)$$
+which is called a {\it dual variable} for $x_k$. This {\it cannot} lead
+to the ambiguity, because both lower and upper bounds of $x_k$ cannot be
+active at the same time,\footnote{If $x_k$ is a fixed variable, we can
+think it as double-bounded variable $l_k\leq x_k\leq u_k$, where
+$l_k=u_k.$} so at least one of $(\lambda_l)_k$ and $(\lambda_u)_k$ must
+be equal to zero, and because these multipliers have different signs,
+the combined multiplier, which is their sum, uniquely defines each of
+them.
+
+\def\arraystretch{1}
+
+Using dual variables $\lambda_k$ the dual system of bound constraints
+(3.17) and (3.18) can be written in the form of so called {\it ``rule of
+signs''} as follows:
+
+\begin{center}
+\begin{tabular}{|@{\,}c@{$\,$}|@{$\,$}c@{$\,$}|@{$\,$}c@{$\,$}|
+@{$\,$}c|c@{$\,$}|@{$\,$}c@{$\,$}|@{$\,$}c@{$\,$}|}
+\hline
+Original bound&\multicolumn{3}{c|}{Minimization}&\multicolumn{3}{c|}
+{Maximization}\\
+\cline{2-7}
+constraint&$(\lambda_l)_k$&$(\lambda_u)_k$&$(\lambda_l)_k+
+(\lambda_u)_k$&$(\lambda_l)_k$&$(\lambda_u)_k$&$(\lambda_l)_k+
+(\lambda_u)_k$\\
+\hline
+$-\infty<x_k<+\infty$&$=0$&$=0$&$\lambda_k=0$&$=0$&$=0$&$\lambda_k=0$\\
+$x_k\geq l_k$&$\geq 0$&$=0$&$\lambda_k\geq 0$&$\leq 0$&$=0$&$\lambda_k
+\leq0$\\
+$x_k\leq u_k$&$=0$&$\leq 0$&$\lambda_k\leq 0$&$=0$&$\geq 0$&$\lambda_k
+\geq0$\\
+$l_k\leq x_k\leq u_k$&$\geq 0$& $\leq 0$& $-\infty\!<\!\lambda_k\!<
+\!+\infty$
+&$\leq 0$& $\geq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$\\
+$x_k=l_k=u_k$&$\geq 0$& $\leq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$&
+$\leq 0$&
+$\geq 0$& $-\infty\!<\!\lambda_k\!<\!+\infty$\\
+\hline
+\end{tabular}
+\end{center}
+
+May note that each primal variable $x_k$ has its dual counterpart
+$\lambda_k$ and vice versa. This allows applying the same partition for
+the vector of dual variables as (3.7):
+$$\left(\begin{array}{@{}c@{}}\lambda_B\\\lambda_N\\\end{array}\right)=
+\Pi\lambda,\eqno(3.21)$$
+where $\lambda_B$ is a vector of dual variables for basic variables
+$x_B$, $\lambda_N$ is a vector of dual variables for non-basic variables
+$x_N$.
+
+By definition, bounds of basic variables are inactive constraints, so in
+any basic solution $\lambda_B=0$. Corresponding values of dual variables
+$\lambda_N$ for non-basic variables $x_N$ can be determined in the
+following way. From the dual system (3.15) we have:
+$$(I\ |-\!A)^T\pi+\lambda=(0\ |\ c)^T,\eqno(3.22)$$
+so multiplying both sides of (3.22) by matrix $\Pi$ gives:
+$$\Pi(I\ |-\!A)^T\pi+\Pi\lambda=\Pi(0\ |\ c)^T.\eqno(3.23)$$
+From (3.9) it follows that
+$$\Pi(I\ |-\!A)^T=[(I\ |-\!A)\Pi^T]^T=(B\ |\ N)^T.\eqno(3.24)$$
+Further, we can apply the partition (3.7) also to the vector of
+objective coefficients (see (3.4)):
+$$\left(\begin{array}{@{}c@{}}c_B\\c_N\\\end{array}\right)=
+\Pi\left(\begin{array}{@{}c@{}}0\\c\\\end{array}\right),\eqno(3.25)$$
+where $c_B$ is a vector of objective coefficients at basic variables,
+$c_N$ is a vector of objective coefficients at non-basic variables.
+Now, substituting (3.24), (3.21), and (3.25) into (3.23), leads to:
+$$(B\ |\ N)^T\pi+(\lambda_B\ |\ \lambda_N)^T=(c_B\ |\ c_N)^T,
+\eqno(3.26)$$
+and transposing both sides of (3.26) gives the system:
+$$\left(\begin{array}{@{}c@{}}B^T\\N^T\\\end{array}\right)\pi+
+\left(\begin{array}{@{}c@{}}\lambda_B\\\lambda_N\\\end{array}\right)=
+\left(\begin{array}{@{}c@{}}c_B\\c_T\\\end{array}\right),\eqno(3.27)$$
+which can be written as follows:
+$$\left\{
+\begin{array}{@{\ }r@{\ }c@{\ }r@{\ }c@{\ }l@{\ }}
+B^T\pi&+&\lambda_B&=&c_B\\
+N^T\pi&+&\lambda_N&=&c_N\\
+\end{array}
+\right.\eqno(3.28)
+$$
+Lagrange multipliers $\pi=(\pi_i)$ correspond to equality constraints
+(3.5) and therefore can have any sign. This allows resolving the first
+subsystem of (3.28) as follows:\footnote{$B^{-T}$ means $(B^T)^{-1}=
+(B^{-1})^T$.}
+$$\pi=B^{-T}(c_B-\lambda_B)=-B^{-T}\lambda_B+B^{-T}c_B,\eqno(3.29)$$
+and substitution of $\pi$ from (3.29) into the second subsystem of
+(3.28) gives:
+$$\lambda_N=-N^T\pi+c_N=N^TB^{-T}\lambda_B+(c_N-N^TB^{-T}c_B).
+\eqno(3.30)$$
+The latter system can be written in the following final form:
+$$\lambda_N=-\Xi^T\lambda_B+d,\eqno(3.31)$$
+where $\Xi$ is the simplex tableau (see (3.12)), and
+$$d=c_N-N^TB^{-T}c_B=c_N+\Xi^Tc_B\eqno(3.32)$$
+is the vector of so called {\it reduced costs} of non-basic variables.
+
+\pagebreak
+
+Above it was said that in any basic solution $\lambda_B=0$, so
+$\lambda_N=d$ as it follows from (3.31).
+
+The system (3.31) is equivalent to the system (3.15) in the sense that
+they both define the same set of points in the space of dual variables
+$\lambda$, which satisfy to these systems. If, moreover, values of all
+dual variables $\lambda_N$ (i.e. reduced costs $d$) satisfy to their
+bound constraints (i.e. to the ``rule of signs''; see the table above),
+the corresponding basic solution is called {\it dual feasible},
+otherwise {\it dual infeasible}. It is understood that any dual feasible
+solution satisfy to all constraints (3.15) and (3.17) (or (3.18) in case
+of maximization).
+
+It can be easily shown that the complementary slackness condition
+(3.19) is always satisfied for {\it any} basic solution. Therefore,
+a basic solution\footnote{It is assumed that a complete basic solution
+has the form $(x,\lambda)$, i.e. it includes primal as well as dual
+variables.} is {\it optimal} if and only if it is primal and dual
+feasible, because in this case it satifies to all the optimality
+conditions (3.14)---(3.19).
+
+\def\arraystretch{1.5}
+
+The meaning of reduced costs $d=(d_j)$ of non-basic variables can be
+explained in the following way. From (3.4), (3.7), and (3.25) it follows
+that:
+$$z=c_B^Tx_B+c_N^Tx_N+c_0.\eqno(3.33)$$
+Substituting $x_B$ from (3.11) into (3.33) we can eliminate basic
+variables and express the objective only through non-basic variables:
+$$
+\begin{array}{r@{\ }c@{\ }l}
+z&=&c_B^T(-B^{-1}Nx_N)+c_N^Tx_N+c_0=\\
+&=&(c_N^T-c_B^TB^{-1}N)x_N+c_0=\\
+&=&(c_N-N^TB^{-T}c_B)^Tx_N+c_0=\\
+&=&d^Tx_N+c_0.
+\end{array}\eqno(3.34)
+$$
+From (3.34) it is seen that reduced cost $d_j$ shows how the objective
+function $z$ depends on non-basic variable $(x_N)_j$ in the neighborhood
+of the current basic solution, i.e. while the current basis remains
+unchanged.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{LP basis routines}
+\label{lpbasis}
+
+\subsection{glp\_bf\_exists---check if the basis factorization exists}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_bf_exists(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+If the basis factorization for the current basis associated with the
+specified problem object exists and therefore is available for
+computations, the routine \verb|glp_bf_exists| returns non-zero.
+Otherwise the routine returns zero.
+
+\subsubsection*{Comments}
+
+Let the problem object have $m$ rows and $n$ columns. In GLPK the
+{\it basis matrix} $B$ is a square non-singular matrix of the order $m$,
+whose columns correspond to basic (auxiliary and/or structural)
+variables. It is defined by the following main
+equality:\footnote{For more details see Subsection \ref{basbgd},
+page \pageref{basbgd}.}
+$$(B\ |\ N)=(I\ |-\!A)\Pi^T,$$
+where $I$ is the unity matrix of the order $m$, whose columns correspond
+to auxiliary variables; $A$ is the original constraint
+$m\times n$-matrix, whose columns correspond to structural variables;
+$(I\ |-\!A)$ is the augmented constraint\linebreak
+$m\times(m+n)$-matrix, whose columns correspond to all (auxiliary and
+structural) variables following in the original order; $\Pi$ is a
+permutation matrix of the order $m+n$; and $N$ is a rectangular
+$m\times n$-matrix, whose columns correspond to non-basic (auxiliary
+and/or structural) variables.
+
+For various reasons it may be necessary to solve linear systems with
+matrix $B$. To provide this possibility the GLPK implementation
+maintains an invertable form of $B$ (that is, some representation of
+$B^{-1}$) called the {\it basis factorization}, which is an internal
+component of the problem object. Typically, the basis factorization is
+computed by the simplex solver, which keeps it in the problem object
+to be available for other computations.
+
+Should note that any changes in the problem object, which affects the
+basis matrix (e.g. changing the status of a row or column, changing
+a basic column of the constraint matrix, removing an active constraint,
+etc.), invalidates the basis factorization. So before calling any API
+routine, which uses the basis factorization, the application program
+must make sure (using the routine \verb|glp_bf_exists|) that the
+factorization exists and therefore available for computations.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\subsection{glp\_factorize---compute the basis factorization}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_factorize(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_factorize| computes the basis factorization for
+the current basis associated with the specified problem
+object.\footnote{The current basis is defined by the current statuses
+of rows (auxiliary variables) and columns (structural variables).}
+
+The basis factorization is computed from ``scratch'' even if it exists,
+so the application program may use the routine \verb|glp_bf_exists|,
+and, if the basis factorization already exists, not to call the routine
+\verb|glp_factorize| to prevent an extra work.
+
+The routine \verb|glp_factorize| {\it does not} compute components of
+the basic solution (i.e. primal and dual values).
+
+\subsubsection*{Returns}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The basis factorization has been successfully computed.\\
+\verb|GLP_EBADB| & The basis matrix is invalid, because the number of
+basic (auxiliary and structural) variables is not the same as the number
+of rows in the problem object.\\
+\verb|GLP_ESING| & The basis matrix is singular within the working
+precision.\\
+\verb|GLP_ECOND| & The basis matrix is ill-conditioned, i.e. its
+condition number is too large.\\
+\end{tabular}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\subsection{glp\_bf\_updated---check if the basis factorization has\\
+been updated}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_bf_updated(glp_prob *lp);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+If the basis factorization has been just computed from ``scratch'', the
+routine \verb|glp_bf_updated| returns zero. Otherwise, if the
+factorization has been updated at least once, the routine returns
+non-zero.
+
+\subsubsection*{Comments}
+
+{\it Updating} the basis factorization means recomputing it to reflect
+changes in the basis matrix. For example, on every iteration of the
+simplex method some column of the current basis matrix is replaced by a
+new column that gives a new basis matrix corresponding to the adjacent
+basis. In this case computing the basis factorization for the adjacent
+basis from ``scratch'' (as the routine \verb|glp_factorize| does) would
+be too time-consuming.
+
+On the other hand, since the basis factorization update is a numeric
+computational procedure, applying it many times may lead to accumulating
+round-off errors. Therefore the basis is periodically refactorized
+(reinverted) from ``scratch'' (with the routine \verb|glp_factorize|)
+that allows improving its numerical properties.
+
+The routine \verb|glp_bf_updated| allows determining if the basis
+factorization has been updated at least once since it was computed from
+``scratch''.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\subsection{glp\_get\_bfcp---retrieve basis factorization control
+parameters}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_get_bfcp| retrieves control parameters, which are
+used on computing and updating the basis factorization associated with
+the specified problem object.
+
+Current values of the control parameters are stored in a \verb|glp_bfcp|
+structure, which the parameter \verb|parm| points to. For a detailed
+description of the structure \verb|glp_bfcp| see comments to the routine
+\verb|glp_set_bfcp| in the next subsection.
+
+\subsubsection*{Comments}
+
+The purpose of the routine \verb|glp_get_bfcp| is two-fold. First, it
+allows the application program obtaining current values of control
+parameters used by internal GLPK routines, which compute and update the
+basis factorization.
+
+The second purpose of this routine is to provide proper values for all
+fields of the structure \verb|glp_bfcp| in the case when the application
+program needs to change some control parameters.
+
+\subsection{glp\_set\_bfcp---change basis factorization control
+parameters}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_bfcp| changes control parameters, which are
+used by internal GLPK routines on computing and updating the basis
+factorization associated with the specified problem object.
+
+New values of the control parameters should be passed in a structure
+\verb|glp_bfcp|, which the parameter \verb|parm| points to. For a
+detailed description of the structure \verb|glp_bfcp| see paragraph
+``Control parameters'' below.
+
+The parameter \verb|parm| can be specified as \verb|NULL|, in which case
+all control parameters are reset to their default values.
+
+\subsubsection*{Comments}
+
+Before changing some control parameters with the routine
+\verb|glp_set_bfcp| the application program should retrieve current
+values of all control parameters with the routine \verb|glp_get_bfcp|.
+This is needed for backward compatibility, because in the future there
+may appear new members in the structure \verb|glp_bfcp|.
+
+Note that new values of control parameters come into effect on a next
+computation of the basis factorization, not immediately.
+
+\subsubsection*{Example}
+
+\begin{verbatim}
+glp_prob *lp;
+glp_bfcp parm;
+. . .
+/* retrieve current values of control parameters */
+glp_get_bfcp(lp, &parm);
+/* change the threshold pivoting tolerance */
+parm.piv_tol = 0.05;
+/* set new values of control parameters */
+glp_set_bfcp(lp, &parm);
+. . .
+\end{verbatim}
+
+\subsubsection*{Control parameters}
+
+This paragraph describes all basis factorization control parameters
+currently used in the package. Symbolic names of control parameters are
+names of corresponding members in the structure \verb|glp_bfcp|.
+
+\def\arraystretch{1}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int type} (default: {\tt GLP\_BF\_FT})} \\
+&Basis factorization type:\\
+&\verb|GLP_BF_FT|---$LU$ + Forrest--Tomlin update;\\
+&\verb|GLP_BF_BG|---$LU$ + Schur complement + Bartels--Golub update;\\
+&\verb|GLP_BF_GR|---$LU$ + Schur complement + Givens rotation update.
+\\
+&In case of \verb|GLP_BF_FT| the update is applied to matrix $U$, while
+in cases of \verb|GLP_BF_BG| and \verb|GLP_BF_GR| the update is applied
+to the Schur complement.
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int lu\_size} (default: {\tt 0})} \\
+&The initial size of the Sparse Vector Area, in non-zeros, used on
+computing $LU$-factorization of the basis matrix for the first time.
+If this parameter is set to 0, the initial SVA size is determined
+automatically.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double piv\_tol} (default: {\tt 0.10})} \\
+&Threshold pivoting (Markowitz) tolerance, 0 $<$ \verb|piv_tol| $<$ 1,
+used on computing $LU$-factorization of the basis matrix. Element
+$u_{ij}$ of the active submatrix of factor $U$ fits to be pivot if it
+satisfies to the stability criterion
+$|u_{ij}| >= {\tt piv\_tol}\cdot\max|u_{i*}|$, i.e. if it is not very
+small in the magnitude among other elements in the same row. Decreasing
+this parameter may lead to better sparsity at the expense of numerical
+accuracy, and vice versa.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int piv\_lim} (default: {\tt 4})} \\
+&This parameter is used on computing $LU$-factorization of the basis
+matrix and specifies how many pivot candidates needs to be considered
+on choosing a pivot element, \verb|piv_lim| $\geq$ 1. If \verb|piv_lim|
+candidates have been considered, the pivoting routine prematurely
+terminates the search with the best candidate found.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int suhl} (default: {\tt GLP\_ON})} \\
+&This parameter is used on computing $LU$-factorization of the basis
+matrix. Being set to {\tt GLP\_ON} it enables applying the following
+heuristic proposed by Uwe Suhl: if a column of the active submatrix has
+no eligible pivot candidates, it is no more considered until it becomes
+a column singleton. In many cases this allows reducing the time needed
+for pivot searching. To disable this heuristic the parameter \verb|suhl|
+should be set to {\tt GLP\_OFF}.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double eps\_tol} (default: {\tt 1e-15})} \\
+&Epsilon tolerance, \verb|eps_tol| $\geq$ 0, used on computing
+$LU$-factorization of the basis matrix. If an element of the active
+submatrix of factor $U$ is less than \verb|eps_tol| in the magnitude,
+it is replaced by exact zero.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double max\_gro} (default: {\tt 1e+10})} \\
+&Maximal growth of elements of factor $U$, \verb|max_gro| $\geq$ 1,
+allowable on computing $LU$-factorization of the basis matrix. If on
+some elimination step the ratio $u_{big}/b_{max}$ (where $u_{big}$ is
+the largest magnitude of elements of factor $U$ appeared in its active
+submatrix during all the factorization process, $b_{max}$ is the largest
+magnitude of elements of the basis matrix to be factorized), the basis
+matrix is considered as ill-conditioned.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int nfs\_max} (default: {\tt 100})} \\
+&Maximal number of additional row-like factors (entries of the eta
+file), \verb|nfs_max| $\geq$ 1, which can be added to $LU$-factorization
+of the basis matrix on updating it with the Forrest--Tomlin technique.
+This parameter is used only once, before $LU$-factorization is computed
+for the first time, to allocate working arrays. As a rule, each update
+adds one new factor (however, some updates may need no addition), so
+this parameter limits the number of updates between refactorizations.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt double upd\_tol} (default: {\tt 1e-6})} \\
+&Update tolerance, 0 $<$ \verb|upd_tol| $<$ 1, used on updating
+$LU$-factorization of the basis matrix with the Forrest--Tomlin
+technique. If after updating the magnitude of some diagonal element
+$u_{kk}$ of factor $U$ becomes less than
+${\tt upd\_tol}\cdot\max(|u_{k*}|, |u_{*k}|)$, the factorization is
+considered as inaccurate.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int nrs\_max} (default: {\tt 100})} \\
+&Maximal number of additional rows and columns, \verb|nrs_max| $\geq$ 1,
+which can be added to $LU$-factorization of the basis matrix on updating
+it with the Schur complement technique. This parameter is used only
+once, before $LU$-factorization is computed for the first time, to
+allocate working arrays. As a rule, each update adds one new row and
+column (however, some updates may need no addition), so this parameter
+limits the number of updates between refactorizations.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int rs\_size} (default: {\tt 0})} \\
+&The initial size of the Sparse Vector Area, in non-zeros, used to
+store non-zero elements of additional rows and columns introduced on
+updating $LU$-factorization of the basis matrix with the Schur
+complement technique. If this parameter is set to 0, the initial SVA
+size is determined automatically.\\
+\end{tabular}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\subsection{glp\_get\_bhead---retrieve the basis header information}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_bhead(glp_prob *lp, int k);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_get_bhead| returns the basis header information
+for the current basis associated with the specified problem object.
+
+\subsubsection*{Returns}
+
+If basic variable $(x_B)_k$, $1\leq k\leq m$, is $i$-th auxiliary
+variable ($1\leq i\leq m$), the routine returns $i$. Otherwise, if
+$(x_B)_k$ is $j$-th structural variable ($1\leq j\leq n$), the routine
+returns $m+j$. Here $m$ is the number of rows and $n$ is the number of
+columns in the problem object.
+
+\subsubsection*{Comments}
+
+Sometimes the application program may need to know which original
+(auxiliary and structural) variable correspond to a given basic
+variable, or, that is the same, which column of the augmented constraint
+matrix $(I\ |-\!A)$ correspond to a given column of the basis matrix
+$B$.
+
+\def\arraystretch{1}
+
+The correspondence is defined as follows:\footnote{For more details see
+Subsection \ref{basbgd}, page \pageref{basbgd}.}
+$$\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right)=
+\Pi\left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)
+\ \ \Leftrightarrow
+\ \ \left(\begin{array}{@{}c@{}}x_R\\x_S\\\end{array}\right)=
+\Pi^T\left(\begin{array}{@{}c@{}}x_B\\x_N\\\end{array}\right),$$
+where $x_B$ is the vector of basic variables, $x_N$ is the vector of
+non-basic variables, $x_R$ is the vector of auxiliary variables
+following in their original order,\footnote{The original order of
+auxiliary and structural variables is defined by the ordinal numbers
+of corresponding rows and columns in the problem object.} $x_S$ is the
+vector of structural variables following in their original order, $\Pi$
+is a permutation matrix (which is a component of the basis
+factorization).
+
+Thus, if $(x_B)_k=(x_R)_i$ is $i$-th auxiliary variable, the routine
+returns $i$, and if $(x_B)_k=(x_S)_j$ is $j$-th structural variable,
+the routine returns $m+j$, where $m$ is the number of rows in the
+problem object.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\subsection{glp\_get\_row\_bind---retrieve row index in the basis\\
+header}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_row_bind(glp_prob *lp, int i);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_row_bind| returns the index $k$ of basic
+variable $(x_B)_k$, $1\leq k\leq m$, which is $i$-th auxiliary variable
+(that is, the auxiliary variable corresponding to $i$-th row),
+$1\leq i\leq m$, in the current basis associated with the specified
+problem object, where $m$ is the number of rows. However, if $i$-th
+auxiliary variable is non-basic, the routine returns zero.
+
+\subsubsection*{Comments}
+
+The routine \verb|glp_get_row_bind| is an inverse to the routine
+\verb|glp_get_bhead|: if \verb|glp_get_bhead|$(lp,k)$ returns $i$,
+\verb|glp_get_row_bind|$(lp,i)$ returns $k$, and vice versa.
+
+\subsection{glp\_get\_col\_bind---retrieve column index in the basis
+header}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_get_col_bind(glp_prob *lp, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_get_col_bind| returns the index $k$ of basic
+variable $(x_B)_k$, $1\leq k\leq m$, which is $j$-th structural
+variable (that is, the structural variable corresponding to $j$-th
+column), $1\leq j\leq n$, in the current basis associated with the
+specified problem object, where $m$ is the number of rows, $n$ is the
+number of columns. However, if $j$-th structural variable is non-basic,
+the routine returns zero.
+
+\subsubsection*{Comments}
+
+The routine \verb|glp_get_col_bind| is an inverse to the routine
+\verb|glp_get_bhead|: if \verb|glp_get_bhead|$(lp,k)$ returns $m+j$,
+\verb|glp_get_col_bind|$(lp,j)$ returns $k$, and vice versa.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\subsection{glp\_ftran---perform forward transformation}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ftran(glp_prob *lp, double x[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ftran| performs forward transformation (FTRAN),
+i.e. it solves the system $Bx=b$, where $B$ is the basis matrix
+associated with the specified problem object, $x$ is the vector of
+unknowns to be computed, $b$ is the vector of right-hand sides.
+
+On entry to the routine elements of the vector $b$ should be stored in
+locations \verb|x[1]|, \dots, \verb|x[m]|, where $m$ is the number of
+rows. On exit the routine stores elements of the vector $x$ in the same
+locations.
+
+\subsection{glp\_btran---perform backward transformation}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_btran(glp_prob *lp, double x[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_btran| performs backward transformation (BTRAN),
+i.e. it solves the system $B^Tx=b$, where $B^T$ is a matrix transposed
+to the basis matrix $B$ associated with the specified problem object,
+$x$ is the vector of unknowns to be computed, $b$ is the vector of
+right-hand sides.
+
+On entry to the routine elements of the vector $b$ should be stored in
+locations \verb|x[1]|, \dots, \verb|x[m]|, where $m$ is the number of
+rows. On exit the routine stores elements of the vector $x$ in the same
+locations.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\subsection{glp\_warm\_up---``warm up'' LP basis}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_warm_up(glp_prob *P);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_warm_up| ``warms up'' the LP basis for the
+specified problem object using current statuses assigned to rows and
+columns (that is, to auxiliary and structural variables).
+
+This operation includes computing factorization of the basis matrix
+(if it does not exist), computing primal and dual components of basic
+solution, and determining the solution status.
+
+\subsubsection*{Returns}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & The operation has been successfully performed.\\
+\verb|GLP_EBADB| & The basis matrix is invalid, because the number of
+basic (auxiliary and structural) variables is not the same as the number
+of rows in the problem object.\\
+\verb|GLP_ESING| & The basis matrix is singular within the working
+precision.\\
+\verb|GLP_ECOND| & The basis matrix is ill-conditioned, i.e. its
+condition number is too large.\\
+\end{tabular}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Simplex tableau routines}
+
+\subsection{glp\_eval\_tab\_row---compute row of the tableau}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_eval_tab_row(glp_prob *lp, int k, int ind[],
+      double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_eval_tab_row| computes a row of the current
+simplex tableau (see Subsection 3.1.1, formula (3.12)), which (row)
+corresponds to some basic variable specified by the parameter $k$ as
+follows: if $1\leq k\leq m$, the basic variable is $k$-th auxiliary
+variable, and if $m+1\leq k\leq m+n$, the basic variable is $(k-m)$-th
+structural variable, where $m$ is the number of rows and $n$ is the
+number of columns in the specified problem object. The basis
+factorization must exist.
+
+The computed row shows how the specified basic variable depends on
+non-basic variables:
+$$x_k=(x_B)_i=\xi_{i1}(x_N)_1+\xi_{i2}(x_N)_2+\dots+\xi_{in}(x_N)_n,$$
+where $\xi_{i1}$, $\xi_{i2}$, \dots, $\xi_{in}$ are elements of the
+simplex table row, $(x_N)_1$, $(x_N)_2$, \dots, $(x_N)_n$ are non-basic
+(auxiliary and structural) variables.
+
+The routine stores column indices and corresponding numeric values of
+non-zero elements of the computed row in unordered sparse format in
+locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
+\dots, \verb|val[len]|, respectively, where $0\leq{\tt len}\leq n$ is
+the number of non-zero elements in the row returned on exit.
+
+Element indices stored in the array \verb|ind| have the same sense as
+index $k$, i.e. indices 1 to $m$ denote auxiliary variables while
+indices $m+1$ to $m+n$ denote structural variables (all these variables
+are obviously non-basic by definition).
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_eval_tab_row| returns \verb|len|, which is the
+number of non-zero elements in the simplex table row stored in the
+arrays \verb|ind| and \verb|val|.
+
+\subsubsection*{Comments}
+
+A row of the simplex table is computed as follows. At first, the
+routine checks that the specified variable $x_k$ is basic and uses the
+permutation matrix $\Pi$ (3.7) to determine index $i$ of basic variable
+$(x_B)_i$, which corresponds to $x_k$.
+
+The row to be computed is $i$-th row of the matrix $\Xi$ (3.12),
+therefore:
+$$\xi_i=e_i^T\Xi=-e_i^TB^{-1}N=-(B^{-T}e_i)^TN,$$
+where $e_i$ is $i$-th unity vector. So the routine performs BTRAN to
+obtain $i$-th row of the inverse $B^{-1}$:
+$$\varrho_i=B^{-T}e_i,$$
+and then computes elements of the simplex table row as inner products:
+$$\xi_{ij}=-\varrho_i^TN_j,\ \ j=1,2,\dots,n,$$
+where $N_j$ is $j$-th column of matrix $N$ (3.9), which (column)
+corresponds to non-basic variable $(x_N)_j$. The permutation matrix
+$\Pi$ is used again to convert indices $j$ of non-basic columns to
+original ordinal numbers of auxiliary and structural variables.
+
+\subsection{glp\_eval\_tab\_col---compute column of the tableau}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_eval_tab_col(glp_prob *lp, int k, int ind[],
+      double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_eval_tab_col| computes a column of the current
+simplex tableau (see Subsection 3.1.1, formula (3.12)), which (column)
+corresponds to some non-basic variable specified by the parameter $k$:
+if $1\leq k\leq m$, the non-basic variable is $k$-th auxiliary variable,
+and if $m+1\leq k\leq m+n$, the non-basic variable is $(k-m)$-th
+structural variable, where $m$ is the number of rows and $n$ is the
+number of columns in the specified problem object. The basis
+factorization must exist.
+
+The computed column shows how basic variables depends on the specified
+non-basic variable $x_k=(x_N)_j$:
+$$
+\begin{array}{r@{\ }c@{\ }l@{\ }l}
+(x_B)_1&=&\dots+\xi_{1j}(x_N)_j&+\dots\\
+(x_B)_2&=&\dots+\xi_{2j}(x_N)_j&+\dots\\
+.\ \ .&.&.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\\
+(x_B)_m&=&\dots+\xi_{mj}(x_N)_j&+\dots\\
+\end{array}
+$$
+where $\xi_{1j}$, $\xi_{2j}$, \dots, $\xi_{mj}$ are elements of the
+simplex table column, $(x_B)_1$, $(x_B)_2$, \dots, $(x_B)_m$ are basic
+(auxiliary and structural) variables.
+
+The routine stores row indices and corresponding numeric values of
+non-zero elements of the computed column in unordered sparse format in
+locations \verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|,
+\dots, \verb|val[len]|, respectively, where $0\leq{\tt len}\leq m$ is
+the number of non-zero elements in the column returned on exit.
+
+Element indices stored in the array \verb|ind| have the same sense as
+index $k$, i.e. indices 1 to $m$ denote auxiliary variables while
+indices $m+1$ to $m+n$ denote structural variables (all these variables
+are obviously basic by definition).
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_eval_tab_col| returns \verb|len|, which is the
+number of non-zero elements in the simplex table column stored in the
+arrays \verb|ind| and \verb|val|.
+
+\subsubsection*{Comments}
+
+A column of the simplex table is computed as follows. At first, the
+routine checks that the specified variable $x_k$ is non-basic and uses
+the permutation matrix $\Pi$ (3.7) to determine index $j$ of non-basic
+variable $(x_N)_j$, which corresponds to $x_k$.
+
+The column to be computed is $j$-th column of the matrix $\Xi$ (3.12),
+therefore:
+$$\Xi_j=\Xi e_j=-B^{-1}Ne_j=-B^{-1}N_j,$$
+where $e_j$ is $j$-th unity vector, $N_j$ is $j$-th column of matrix
+$N$ (3.9). So the routine performs FTRAN to transform $N_j$ to the
+simplex table column $\Xi_j=(\xi_{ij})$ and uses the permutation matrix
+$\Pi$ to convert row indices $i$ to original ordinal numbers of
+auxiliary and structural variables.
+
+\newpage
+
+\subsection{glp\_transform\_row---transform explicitly specified\\
+row}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_transform_row(glp_prob *P, int len, int ind[],
+      double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_transform_row| performs the same operation as the
+routine \verb|glp_eval_tab_row| with exception that the row to be
+transformed is specified explicitly as a sparse vector.
+
+The explicitly specified row may be thought as a linear form:
+$$x=a_1x_{m+1}+a_2x_{m+2}+\dots+a_nx_{m+n},$$
+where $x$ is an auxiliary variable for this row, $a_j$ are coefficients
+of the linear form, $x_{m+j}$ are structural variables.
+
+On entry column indices and numerical values of non-zero coefficients
+$a_j$ of the specified row should be placed in locations \verb|ind[1]|,
+\dots, \verb|ind[len]| and \verb|val[1]|, \dots, \verb|val[len]|, where
+\verb|len| is number of non-zero coefficients.
+
+This routine uses the system of equality constraints and the current
+basis in order to express the auxiliary variable $x$ through the current
+non-basic variables (as if the transformed row were added to the problem
+object and the auxiliary variable $x$ were basic), i.e. the resultant
+row has the form:
+$$x=\xi_1(x_N)_1+\xi_2(x_N)_2+\dots+\xi_n(x_N)_n,$$
+where $\xi_j$ are influence coefficients, $(x_N)_j$ are non-basic
+(auxiliary and structural) variables, $n$ is the number of columns in
+the problem object.
+
+On exit the routine stores indices and numerical values of non-zero
+coefficients $\xi_j$ of the resultant row in locations \verb|ind[1]|,
+\dots, \verb|ind[len']| and \verb|val[1]|, \dots, \verb|val[len']|,
+where $0\leq{\tt len'}\leq n$ is the number of non-zero coefficients in
+the resultant row returned by the routine. Note that indices of
+non-basic variables stored in the array \verb|ind| correspond to
+original ordinal numbers of variables: indices 1 to $m$ mean auxiliary
+variables and indices $m+1$ to $m+n$ mean structural ones.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_transform_row| returns \verb|len'|, the number of
+non-zero coefficients in the resultant row stored in the arrays
+\verb|ind| and \verb|val|.
+
+\subsection{glp\_transform\_col---transform explicitly specified\\
+column}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_transform_col(glp_prob *P, int len, int ind[],
+      double val[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_transform_col| performs the same operation as the
+routine \verb|glp_eval_tab_col| with exception that the column to be
+transformed is specified explicitly as a sparse vector.
+
+The explicitly specified column may be thought as it were added to
+the original system of equality constraints:
+$$
+\begin{array}{l@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r}
+x_1&=&a_{11}x_{m+1}&+\dots+&a_{1n}x_{m+n}&+&a_1x \\
+x_2&=&a_{21}x_{m+1}&+\dots+&a_{2n}x_{m+n}&+&a_2x \\
+\multicolumn{7}{c}
+{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
+x_m&=&a_{m1}x_{m+1}&+\dots+&a_{mn}x_{m+n}&+&a_mx \\
+\end{array}
+$$
+where $x_i$ are auxiliary variables, $x_{m+j}$ are structural variables
+(presented in the problem object), $x$ is a structural variable for the
+explicitly specified column, $a_i$ are constraint coefficients at $x$.
+
+On entry row indices and numerical values of non-zero coefficients
+$a_i$ of the specified column should be placed in locations
+\verb|ind[1]|, \dots, \verb|ind[len]| and \verb|val[1]|, \dots,
+\verb|val[len]|, where \verb|len| is number of non-zero coefficients.
+
+This routine uses the system of equality constraints and the current
+basis in order to express the current basic variables through the
+structural variable $x$ (as if the transformed column were added to the
+problem object and the variable $x$ were non-basic):
+$$
+\begin{array}{l@{\ }c@{\ }r}
+(x_B)_1&=\dots+&\xi_{1}x\\
+(x_B)_2&=\dots+&\xi_{2}x\\
+\multicolumn{3}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .}\\
+(x_B)_m&=\dots+&\xi_{m}x\\
+\end{array}
+$$
+where $\xi_i$ are influence coefficients, $x_B$ are basic (auxiliary
+and structural) variables, $m$ is the number of rows in the problem
+object.
+
+On exit the routine stores indices and numerical values of non-zero
+coefficients $\xi_i$ of the resultant column in locations \verb|ind[1]|,
+\dots, \verb|ind[len']| and \verb|val[1]|, \dots, \verb|val[len']|,
+where $0\leq{\tt len'}\leq m$ is the number of non-zero coefficients in
+the resultant column returned by the routine. Note that indices of basic
+variables stored in the array \verb|ind| correspond to original ordinal
+numbers of variables, i.e. indices 1 to $m$ mean auxiliary variables,
+indices $m+1$ to $m+n$ mean structural ones.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_transform_col| returns \verb|len'|, the number of
+non-zero coefficients in the resultant column stored in the arrays
+\verb|ind| and \verb|val|.
+
+\subsection{glp\_prim\_rtest---perform primal ratio test}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_prim_rtest| performs the primal ratio test using
+an explicitly specified column of the simplex table.
+
+The current basic solution associated with the LP problem object must be
+primal feasible.
+
+The explicitly specified column of the simplex table shows how the basic
+variables $x_B$ depend on some non-basic variable $x$ (which is not
+necessarily presented in the problem object):
+$$
+\begin{array}{l@{\ }c@{\ }r}
+(x_B)_1&=\dots+&\xi_{1}x\\
+(x_B)_2&=\dots+&\xi_{2}x\\
+\multicolumn{3}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .}\\
+(x_B)_m&=\dots+&\xi_{m}x\\
+\end{array}
+$$
+
+The column is specifed on entry to the routine in sparse format. Ordinal
+numbers of basic variables $(x_B)_i$ should be placed in locations
+\verb|ind[1]|, \dots, \verb|ind[len]|, where ordinal number 1 to $m$
+denote auxiliary variables, and ordinal numbers $m+1$ to $m+n$ denote
+structural variables. The corresponding non-zero coefficients $\xi_i$
+should be placed in locations \verb|val[1]|, \dots, \verb|val[len]|. The
+arrays \verb|ind| and \verb|val| are not changed by the routine.
+
+The parameter \verb|dir| specifies direction in which the variable $x$
+changes on entering the basis: $+1$ means increasing, $-1$ means
+decreasing.
+
+The parameter \verb|eps| is an absolute tolerance (small positive
+number, say, $10^{-9}$) used by the routine to skip $\xi_i$'s whose
+magnitude is less than \verb|eps|.
+
+The routine determines which basic variable (among those specified in
+\verb|ind[1]|, \dots, \verb|ind[len]|) reaches its (lower or upper)
+bound first before any other basic variables do, and which, therefore,
+should leave the basis in order to keep primal feasibility.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_prim_rtest| returns the index, \verb|piv|, in the
+arrays \verb|ind| and \verb|val| corresponding to the pivot element
+chosen, $1\leq$ \verb|piv| $\leq$ \verb|len|. If the adjacent basic
+solution is primal unbounded, and therefore the choice cannot be made,
+the routine returns zero.
+
+\subsubsection*{Comments}
+
+If the non-basic variable $x$ is presented in the LP problem object, the
+input column can be computed with the routine \verb|glp_eval_tab_col|;
+otherwise, it can be computed with the routine \verb|glp_transform_col|.
+
+\subsection{glp\_dual\_rtest---perform dual ratio test}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_dual_rtest| performs the dual ratio test using
+an explicitly specified row of the simplex table.
+
+The current basic solution associated with the LP problem object must be
+dual feasible.
+
+The explicitly specified row of the simplex table is a linear form
+that shows how some basic variable $x$ (which is not necessarily
+presented in the problem object) depends on non-basic variables $x_N$:
+$$x=\xi_1(x_N)_1+\xi_2(x_N)_2+\dots+\xi_n(x_N)_n.$$
+
+The row is specified on entry to the routine in sparse format. Ordinal
+numbers of non-basic variables $(x_N)_j$ should be placed in locations
+\verb|ind[1]|, \dots, \verb|ind[len]|, where ordinal numbers 1 to $m$
+denote auxiliary variables, and ordinal numbers $m+1$ to $m+n$ denote
+structural variables. The corresponding non-zero coefficients $\xi_j$
+should be placed in locations \verb|val[1]|, \dots, \verb|val[len]|.
+The arrays \verb|ind| and \verb|val| are not changed by the routine.
+
+The parameter \verb|dir| specifies direction in which the variable $x$
+changes on leaving the basis: $+1$ means that $x$ goes on its lower
+bound, so its reduced cost (dual variable) is increasing (minimization)
+or decreasing (maximization); $-1$ means that $x$ goes on its upper
+bound, so its reduced cost is decreasing (minimization) or increasing
+(maximization).
+
+The parameter \verb|eps| is an absolute tolerance (small positive
+number, say, $10^{-9}$) used by the routine to skip $\xi_j$'s whose
+magnitude is less than \verb|eps|.
+
+The routine determines which non-basic variable (among those specified
+in \verb|ind[1]|, \dots, \verb|ind[len]|) should enter the basis in
+order to keep dual feasibility, because its reduced cost reaches the
+(zero) bound first before this occurs for any other non-basic variables.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_dual_rtest| returns the index, \verb|piv|, in the
+arrays \verb|ind| and \verb|val| corresponding to the pivot element
+chosen, $1\leq$ \verb|piv| $\leq$ \verb|len|. If the adjacent basic
+solution is dual unbounded, and therefore the choice cannot be made,
+the routine returns zero.
+
+\subsubsection*{Comments}
+
+If the basic variable $x$ is presented in the LP problem object, the
+input row can be computed with the routine \verb|glp_eval_tab_row|;
+otherwise, it can be computed with the routine \verb|glp_transform_row|.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Post-optimal analysis routines}
+
+\subsection{glp\_analyze\_bound---analyze active bound of non-basic
+variable}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_analyze_bound(glp_prob *P, int k, double *limit1,
+      int *var1, double *limit2, int *var2);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_analyze_bound| analyzes the effect of varying the
+active bound of specified non-basic variable.
+
+The non-basic variable is specified by the parameter $k$, where
+$1\leq k\leq m$ means auxiliary variable of corresponding row, and
+$m+1\leq k\leq m+n$ means structural variable (column).
+
+Note that the current basic solution must be optimal, and the basis
+factorization must exist.
+
+Results of the analysis have the following meaning.
+
+\verb|value1| is the minimal value of the active bound, at which the
+basis still remains primal feasible and thus optimal. \verb|-DBL_MAX|
+means that the active bound has no lower limit.
+
+\verb|var1| is the ordinal number of an auxiliary (1 to $m$) or
+structural ($m+1$ to $m+n$) basic variable, which reaches its bound
+first and thereby limits further decreasing the active bound being
+analyzed. if \verb|value1| = \verb|-DBL_MAX|, \verb|var1| is set to 0.
+
+\verb|value2| is the maximal value of the active bound, at which the
+basis still remains primal feasible and thus optimal. \verb|+DBL_MAX|
+means that the active bound has no upper limit.
+
+\verb|var2| is the ordinal number of an auxiliary (1 to $m$) or
+structural ($m+1$ to $m+n$) basic variable, which reaches its bound
+first and thereby limits further increasing the active bound being
+analyzed. if \verb|value2| = \verb|+DBL_MAX|, \verb|var2| is set to 0.
+
+The parameters \verb|value1|, \verb|var1|, \verb|value2|, \verb|var2|
+can be specified as \verb|NULL|, in which case corresponding information
+is not stored.
+
+\newpage
+
+\subsection{glp\_analyze\_coef---analyze objective coefficient at basic
+variable}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_analyze_coef(glp_prob *P, int k, double *coef1,
+      int *var1, double *value1, double *coef2, int *var2,
+      double *value2);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_analyze_coef| analyzes the effect of varying the
+objective coefficient at specified basic variable.
+
+The basic variable is specified by the parameter $k$, where
+$1\leq k\leq m$ means auxiliary variable of corresponding row, and
+$m+1\leq k\leq m+n$ means structural variable (column).
+
+Note that the current basic solution must be optimal, and the basis
+factorization must exist.
+
+Results of the analysis have the following meaning.
+
+\verb|coef1| is the minimal value of the objective coefficient, at
+which the basis still remains dual feasible and thus optimal.
+\verb|-DBL_MAX| means that the objective coefficient has no lower limit.
+
+\verb|var1| is the ordinal number of an auxiliary (1 to $m$) or
+structural ($m+1$ to $m+n$) non-basic variable, whose reduced cost
+reaches its zero bound first and thereby limits further decreasing the
+objective coefficient being analyzed. If \verb|coef1| = \verb|-DBL_MAX|,
+\verb|var1| is set to 0.
+
+\verb|value1| is value of the basic variable being analyzed in an
+adjacent basis, which is defined as follows. Let the objective
+coefficient reaches its minimal value (\verb|coef1|) and continues
+decreasing. Then the reduced cost of the limiting non-basic variable
+(\verb|var1|) becomes dual infeasible and the current basis becomes
+non-optimal that forces the limiting non-basic variable to enter the
+basis replacing there some basic variable that leaves the basis to keep
+primal feasibility. Should note that on determining the adjacent basis
+current bounds of the basic variable being analyzed are ignored as if
+it were free (unbounded) variable, so it cannot leave the basis. It may
+happen that no dual feasible adjacent basis exists, in which case
+\verb|value1| is set to \verb|-DBL_MAX| or \verb|+DBL_MAX|.
+
+\verb|coef2| is the maximal value of the objective coefficient, at
+which the basis still remains dual feasible and thus optimal.
+\verb|+DBL_MAX| means that the objective coefficient has no upper limit.
+
+\verb|var2| is the ordinal number of an auxiliary (1 to $m$) or
+structural ($m+1$ to $m+n$) non-basic variable, whose reduced cost
+reaches its zero bound first and thereby limits further increasing the
+objective coefficient being analyzed. If \verb|coef2| = \verb|+DBL_MAX|,
+\verb|var2| is set to 0.
+
+\verb|value2| is value of the basic variable being analyzed in an
+adjacent basis, which is defined exactly in the same way as
+\verb|value1| above with exception that now the objective coefficient
+is increasing.
+
+The parameters \verb|coef1|, \verb|var1|, \verb|value1|, \verb|coef2|,
+\verb|var2|, \verb|value2| can be specified as \verb|NULL|, in which
+case corresponding information is not stored.
+
+%* eof *%
Index: deps/glpk/doc/glpk05.tex
===================================================================
--- deps/glpk/doc/glpk05.tex	(revision 9)
+++ deps/glpk/doc/glpk05.tex	(revision 9)
@@ -0,0 +1,1100 @@
+%* glpk05.tex *%
+
+\chapter{Branch-and-Cut API Routines}
+
+\section{Introduction}
+
+\subsection{Using the callback routine}
+
+The GLPK MIP solver based on the branch-and-cut method allows the
+application program to control the solution process. This is attained
+by means of the user-defined callback routine, which is called by the
+solver at various points of the branch-and-cut algorithm.
+
+The callback routine passed to the MIP solver should be written by the
+user and has the following specification:\footnote{The name
+{\tt foo\_bar} used here is a placeholder for the callback routine
+name.}
+
+\begin{verbatim}
+   void foo_bar(glp_tree *tree, void *info);
+\end{verbatim}
+
+\noindent
+where \verb|tree| is a pointer to the data structure \verb|glp_tree|,
+which should be used on subsequent calls to branch-and-cut interface
+routines, and \verb|info| is a transit pointer passed to the routine
+\verb|glp_intopt|, which may be used by the application program to pass
+some external data to the callback routine.
+
+The callback routine is passed to the MIP solver through the control
+parameter structure \verb|glp_iocp| (see Chapter ``Basic API Routines'',
+Section ``Mixed integer programming routines'', Subsection ``Solve MIP
+problem with the branch-and-cut method'') as follows:
+
+\newpage
+
+\begin{verbatim}
+   glp_prob *mip;
+   glp_iocp parm;
+   . . .
+   glp_init_iocp(&parm);
+   . . .
+   parm.cb_func = foo_bar;
+   parm.cb_info = ... ;
+   ret = glp_intopt(mip, &parm);
+   . . .
+\end{verbatim}
+
+To determine why it is being called by the MIP solver the callback
+routine should use the routine \verb|glp_ios_reason| (described in this
+section below), which returns a code indicating the reason for calling.
+Depending on the reason the callback routine may perform necessary
+actions to control the solution process.
+
+The reason codes, which correspond to various point of the
+branch-and-cut algorithm implemented in the MIP solver, are described
+in Subsection ``Reasons for calling the callback routine'' below.
+
+To ignore calls for reasons, which are not processed by the callback
+routine, it should just return to the MIP solver doing nothing. For
+example:
+
+\begin{verbatim}
+void foo_bar(glp_tree *tree, void *info)
+{     . . .
+      switch (glp_ios_reason(tree))
+      {  case GLP_IBRANCH:
+            . . .
+            break;
+         case GLP_ISELECT:
+            . . .
+            break;
+         default:
+            /* ignore call for other reasons */
+            break;
+      }
+      return;
+}
+\end{verbatim}
+
+To control the solution process as well as to obtain necessary
+information the callback routine may use the branch-and-cut API
+routines described in this chapter. Names of all these routines begin
+with `\verb|glp_ios_|'.
+
+\subsection{Branch-and-cut algorithm}
+
+This section gives a schematic description of the branch-and-cut
+algorithm as it is implemented in the GLPK MIP solver.
+
+\medskip
+
+{\it 1. Initialization}
+
+Set $L:=\{P_0\}$, where $L$ is the {\it active list} (i.e. the list of
+active subproblems), $P_0$ is the original MIP problem to be solved.
+
+Set $z^{\it best}:=+\infty$ (in case of minimization) or
+$z^{\it best}:=-\infty$ (in case of maximization), where $z^{\it best}$
+is {\it incumbent value}, i.e. an upper (minimization) or lower
+(maximization) global bound for $z^{\it opt}$, the optimal objective
+value for $P^0$.
+
+\medskip
+
+{\it 2. Subproblem selection}
+
+If $L=\varnothing$ then GO TO 9.
+
+Select $P\in L$, i.e. make active subproblem $P$ current.
+
+\medskip
+
+{\it 3. Solving LP relaxation}
+
+Solve $P^{\it LP}$, which is LP relaxation of $P$.
+
+If $P^{\it LP}$ has no primal feasible solution then GO TO 8.
+
+Let $z^{\it LP}$ be the optimal objective value for $P^{\it LP}$.
+
+If $z^{\it LP}\geq z^{\it best}$ (in case of minimization) or
+$z^{\it LP}\leq z^{\rm best}$ (in case of maximization) then GO TO 8.
+
+\medskip
+
+{\it 4. Adding ``lazy'' constraints}
+
+Let $x^{\it LP}$ be the optimal solution to $P^{\it LP}$.
+
+If there are ``lazy'' constraints (i.e. essential constraints not
+included in the original MIP problem $P_0$), which are violated at the
+optimal point $x^{\it LP}$, add them to $P$, and GO TO 3.
+
+\medskip
+
+{\it 5. Check for integrality}
+
+Let $x_j$ be a variable, which is required to be integer, and let
+$x^{\it LP}_j\in x^{\it LP}$ be its value in the optimal solution to
+$P^{\it LP}$.
+
+If $x^{\it LP}_j$ are integral for all integer variables, then a better
+integer feasible solution is found. Store its components, set
+$z^{\it best}:=z^{\it LP}$, and GO TO 8.
+
+\medskip
+
+{\it 6. Adding cutting planes}
+
+If there are cutting planes (i.e. valid constraints for $P$),
+which are violated at the optimal point $x^{\it LP}$, add them to $P$,
+and GO TO 3.
+
+\medskip
+
+{\it 7. Branching}
+
+Select {\it branching variable} $x_j$, i.e. a variable, which is
+required to be integer, and whose value $x^{\it LP}_j\in x^{\it LP}$ is
+fractional in the optimal solution to $P^{\it LP}$.
+
+Create new subproblem $P^D$ (so called {\it down branch}), which is
+identical to the current subproblem $P$ with exception that the upper
+bound of $x_j$ is replaced by $\lfloor x^{\it LP}_j\rfloor$. (For
+example, if $x^{\it LP}_j=3.14$, the new upper bound of $x_j$ in the
+down branch will be $\lfloor 3.14\rfloor=3$.)
+
+Create new subproblem $P^U$ (so called {\it up branch}), which is
+identical to the current subproblem $P$ with exception that the lower
+bound of $x_j$ is replaced by $\lceil x^{\it LP}_j\rceil$. (For example,
+if $x^{\it LP}_j=3.14$, the new lower bound of $x_j$ in the up branch
+will be $\lceil 3.14\rceil=4$.)
+
+Set $L:=(L\backslash\{P\})\cup\{P^D,P^U\}$, i.e. remove the current
+subproblem $P$ from the active list $L$ and add two new subproblems
+$P^D$ and $P^U$ to it. Then GO TO 2.
+
+\medskip
+
+{\it 8. Pruning}
+
+Remove from the active list $L$ all subproblems (including the current
+one), whose local bound $\widetilde{z}$ is not better than the global
+bound $z^{\it best}$, i.e. set $L:=L\backslash\{P\}$ for all $P$, where
+$\widetilde{z}\geq z^{\it best}$ (in case of minimization) or
+$\widetilde{z}\leq z^{\it best}$ (in case of maximization), and then
+GO TO 2.
+
+The local bound $\widetilde{z}$ for subproblem $P$ is an lower
+(minimization) or upper (maximization) bound for integer optimal
+solution to {\it this} subproblem (not to the original problem). This
+bound is local in the sense that only subproblems in the subtree rooted
+at node $P$ cannot have better integer feasible solutions. Note that
+the local bound is not necessarily the optimal objective value to LP
+relaxation $P^{\it LP}$.
+
+\medskip
+
+{\it 9. Termination}
+
+If $z^{\it best}=+\infty$ (in case of minimization) or
+$z^{\it best}=-\infty$ (in case of maximization), the original problem
+$P_0$ has no integer feasible solution. Otherwise, the last integer
+feasible solution stored on step 5 is the integer optimal solution to
+the original problem $P_0$ with $z^{\it opt}=z^{\it best}$. STOP.
+
+\subsection{The search tree}
+
+On the branching step of the branch-and-cut algorithm the current
+subproblem is divided into two\footnote{In more general cases the
+current subproblem may be divided into more than two subproblems.
+However, currently such feature is not used in GLPK.} new subproblems,
+so the set of all subproblems can be represented in the form of a rooted
+tree, which is called the {\it search} or {\it branch-and-bound} tree.
+An example of the search tree is shown on Fig.~1. Each node of the
+search tree corresponds to a subproblem, so the terms `node' and
+`subproblem' may be used synonymously.
+
+\newpage
+
+\begin{figure}[t]
+\noindent\hfil
+\xymatrix @R=20pt @C=10pt
+{&&&&&&*+<14pt>[o][F=]{A}\ar@{-}[dllll]\ar@{-}[dr]\ar@{-}[drrrr]&&&&\\
+&&*+<14pt>[o][F=]{B}\ar@{-}[dl]\ar@{-}[dr]&&&&&*+<14pt>[o][F=]{C}
+\ar@{-}[dll]\ar@{-}[dr]\ar@{-}[drrr]&&&*+<14pt>[o][F-]{\times}\\
+&*+<14pt>[o][F-]{\times}\ar@{-}[dl]\ar@{-}[d]\ar@{-}[dr]&&
+*+<14pt>[o][F-]{D}&&*+<14pt>[o][F=]{E}\ar@{-}[dl]\ar@{-}[dr]&&&
+*+<14pt>[o][F=]{F}\ar@{-}[dl]\ar@{-}[dr]&&*+<14pt>[o][F-]{G}\\
+*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}&*+<14pt>[o][F-]{\times}
+&&*+<14pt>[][F-]{H}&&*+<14pt>[o][F-]{I}&*+<14pt>[o][F-]{\times}&&
+*+<14pt>[o][F-]{J}&\\}
+
+\bigskip
+
+\noindent\hspace{.8in}
+\xymatrix @R=11pt
+{*+<20pt>[][F-]{}&*\txt{\makebox[1in][l]{Current}}&&
+*+<20pt>[o][F-]{}&*\txt{\makebox[1in][l]{Active}}\\
+*+<20pt>[o][F=]{}&*\txt{\makebox[1in][l]{Non-active}}&&
+*+<14pt>[o][F-]{\times}&*\txt{\makebox[1in][l]{Fathomed}}\\
+}
+
+\begin{center}
+Fig. 1. An example of the search tree.
+\end{center}
+\end{figure}
+
+In GLPK each node may have one of the following four statuses:
+
+$\bullet$ {\it current node} is the active node currently being
+processed;
+
+$\bullet$ {\it active node} is a leaf node, which still has to be
+processed;
+
+$\bullet$ {\it non-active node} is a node, which has been processed,
+but not fathomed;
+
+$\bullet$ {\it fathomed node} is a node, which has been processed and
+fathomed.
+
+In the data structure representing the search tree GLPK keeps only
+current, active, and non-active nodes. Once a node has been fathomed,
+it is removed from the tree data structure.
+
+Being created each node of the search tree is assigned a distinct
+positive integer called the {\it subproblem reference number}, which
+may be used by the application program to specify a particular node of
+the tree. The root node corresponding to the original problem to be
+solved is always assigned the reference number 1.
+
+\subsection{Current subproblem}
+
+The current subproblem is a MIP problem corresponding to the current
+node of the search tree. It is represented as the GLPK problem object
+(\verb|glp_prob|) that allows the application program using API routines
+to access its content in the standard way. If the MIP presolver is not
+used, it is the original problem object passed to the routine
+\verb|glp_intopt|; otherwise, it is an internal problem object built by
+the MIP presolver.
+
+Note that the problem object is used by the MIP solver itself during
+the solution process for various purposes (to solve LP relaxations, to
+perfom branching, etc.), and even if the MIP presolver is not used, the
+current content of the problem object may differ from its original
+content. For example, it may have additional rows, bounds of some rows
+and columns may be changed, etc. In particular, LP segment of the
+problem object corresponds to LP relaxation of the current subproblem.
+However, on exit from the MIP solver the content of the problem object
+is restored to its original state.
+
+To obtain information from the problem object the application program
+may use any API routines, which do not change the object. Using API
+routines, which change the problem object, is restricted to stipulated
+cases.
+
+\subsection{The cut pool}
+
+The {\it cut pool} is a set of cutting plane constraints maintained by
+the MIP solver. It is used by the GLPK cut generation routines and may
+be used by the application program in the same way, i.e. rather than
+to add cutting plane constraints directly to the problem object the
+application program may store them to the cut pool. In the latter case
+the solver looks through the cut pool, selects efficient constraints,
+and adds them to the problem object.
+
+\subsection{Reasons for calling the callback routine}
+
+The callback routine may be called by the MIP solver for the following
+reasons.
+
+\subsubsection*{Request for subproblem selection}
+
+The callback routine is called with the reason code \verb|GLP_ISELECT|
+if the current subproblem has been fathomed and therefore there is no
+current subproblem.
+
+In response the callback routine may select some subproblem from the
+active list and pass its reference number to the solver using the
+routine \verb|glp_ios_select_node|, in which case the solver continues
+the search from the specified active subproblem. If no selection is made
+by the callback routine, the solver uses a backtracking technique
+specified by the control parameter \verb|bt_tech|.
+
+To explore the active list (i.e. active nodes of the branch-and-bound
+tree) the callback routine may use the routines \verb|glp_ios_next_node|
+and \verb|glp_ios_prev_node|.
+
+\subsubsection*{Request for preprocessing}
+
+The callback routine is called with the reason code \verb|GLP_IPREPRO|
+if the current subproblem has just been selected from the active list
+and its LP relaxation is not solved yet.
+
+In response the callback routine may perform some preprocessing of the
+current subproblem like tightening bounds of some variables or removing
+bounds of some redundant constraints.
+
+\subsubsection*{Request for row generation}
+
+The callback routine is called with the reason code \verb|GLP_IROWGEN|
+if LP relaxation of the current subproblem has just been solved to
+optimality and its objective value is better than the best known integer
+feasible solution.
+
+In response the callback routine may add one or more ``lazy''
+constraints (rows), which are violated by the current optimal solution
+of LP relaxation, using API routines \verb|glp_add_rows|,
+\verb|glp_set_row_name|, \verb|glp_set_row_bnds|, and
+\verb|glp_set_mat_row|, in which case the solver will perform
+re-optimization of LP relaxation. If there are no violated constraints,
+the callback routine should just return.
+
+Optimal solution components for LP relaxation can be obtained with API
+routines \verb|glp_get_obj_val|, \verb|glp_get_row_prim|,
+\verb|glp_get_row_dual|, \verb|glp_get_col_prim|, and
+\verb|glp_get_col_dual|.
+
+\subsubsection*{Request for heuristic solution}
+
+The callback routine is called with the reason code \verb|GLP_IHEUR|
+if LP relaxation of the current subproblem being solved to optimality
+is integer infeasible (i.e. values of some structural variables of
+integer kind are fractional), though its objective value is better than
+the best known integer feasible solution.
+
+In response the callback routine may try applying a primal heuristic
+to find an integer feasible solution,\footnote{Integer feasible to the
+original MIP problem, not to the current subproblem.} which is better
+than the best known one. In case of success the callback routine may
+store such better solution in the problem object using the routine
+\verb|glp_ios_heur_sol|.
+
+\subsubsection*{Request for cut generation}
+
+The callback routine is called with the reason code \verb|GLP_ICUTGEN|
+if LP relaxation of the current subproblem being solved to optimality
+is integer infeasible (i.e. values of some structural variables of
+integer kind are fractional), though its objective value is better than
+the best known integer feasible solution.
+
+In response the callback routine may reformulate the {\it current}
+subproblem (before it will be splitted up due to branching) by adding to
+the problem object one or more {\it cutting plane constraints}, which
+cut off the fractional optimal point from the MIP
+polytope.\footnote{Since these constraints are added to the current
+subproblem, they may be globally as well as locally valid.}
+
+Adding cutting plane constraints may be performed in two ways.
+One way is the same as for the reason code \verb|GLP_IROWGEN| (see
+above), in which case the callback routine adds new rows corresponding
+to cutting plane constraints directly to the current subproblem.
+
+The other way is to add cutting plane constraints to the {\it cut pool},
+a set of cutting plane constraints maintained by the solver, rather than
+directly to the current subproblem. In this case after return from the
+callback routine the solver looks through the cut pool, selects
+efficient cutting plane constraints, adds them to the current
+subproblem, drops other constraints, and then performs re-optimization.
+
+\subsubsection*{Request for branching}
+
+The callback routine is called with the reason code \verb|GLP_IBRANCH|
+if LP relaxation of the current subproblem being solved to optimality
+is integer infeasible (i.e. values of some structural variables of
+integer kind are fractional), though its objective value is better than
+the best known integer feasible solution.
+
+In response the callback routine may choose some variable suitable for
+branching (i.e. integer variable, whose value in optimal solution to
+LP relaxation of the current subproblem is fractional) and pass its
+ordinal number to the solver using the routine
+\verb|glp_ios_branch_upon|, in which case the solver splits the current
+subproblem in two new subproblems and continues the search. If no choice
+is made by the callback routine, the solver uses a branching technique
+specified by the control parameter \verb|br_tech|.
+
+\subsubsection*{Better integer solution found}
+
+The callback routine is called with the reason code \verb|GLP_IBINGO|
+if LP relaxation of the current subproblem being solved to optimality
+is integer feasible (i.e. values of all structural variables of integer
+kind are integral within the working precision) and its objective value
+is better than the best known integer feasible solution.
+
+Optimal solution components for LP relaxation can be obtained in the
+same way as for the reason code \verb|GLP_IROWGEN| (see above).
+
+Components of the new MIP solution can be obtained with API routines
+\verb|glp_mip_obj_val|, \verb|glp_mip_row_val|, and
+\verb|glp_mip_col_val|. Note, however, that due to row/cut generation
+there may be additional rows in the problem object.
+
+The difference between optimal solution to LP relaxation and
+corresponding MIP solution is that in the former case some structural
+variables of integer kind (namely, basic variables) may have values,
+which are close to nearest integers within the working precision, while
+in the latter case all such variables have exact integral values.
+
+The reason \verb|GLP_IBINGO| is intended only for informational
+purposes, so the callback routine should not modify the problem object
+in this case.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Basic routines}
+
+\subsection{glp\_ios\_reason---determine reason for calling the
+callback routine}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_reason(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_reason| returns a code, which indicates why
+the user-defined callback routine is being called:
+
+\verb|GLP_ISELECT|---request for subproblem selection;
+
+\verb|GLP_IPREPRO|---request for preprocessing;
+
+\verb|GLP_IROWGEN|---request for row generation;
+
+\verb|GLP_IHEUR  |---request for heuristic solution;
+
+\verb|GLP_ICUTGEN|---request for cut generation;
+
+\verb|GLP_IBRANCH|---request for branching;
+
+\verb|GLP_IBINGO |---better integer solution found.
+
+\subsection{glp\_ios\_get\_prob---access the problem object}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+glp_prob *glp_ios_get_prob(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_get_prob| can be called from the user-defined
+callback routine to access the problem object, which is used by the MIP
+solver. It is the original problem object passed to the routine
+\verb|glp_intopt| if the MIP presolver is not used; otherwise it is an
+internal problem object built by the presolver.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_get_prob| returns a pointer to the problem
+object used by the MIP solver.
+
+\subsubsection*{Comments}
+
+To obtain various information about the problem instance the callback
+routine can access the problem object (i.e. the object of type
+\verb|glp_prob|) using the routine \verb|glp_ios_get_prob|. It is the
+original problem object passed to the routine \verb|glp_intopt| if the
+MIP presolver is not used; otherwise it is an internal problem object
+built by the presolver.
+
+\subsection{glp\_ios\_row\_attr---determine additional row attributes}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_row_attr| retrieves additional attributes of
+$i$-th row of the current subproblem and stores them in the structure
+\verb|glp_attr|, which the parameter \verb|attr| points to.
+
+The structure \verb|glp_attr| has the following fields:
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int level}}\\
+&Subproblem level at which the row was created. (If \verb|level| = 0,
+the row was added either to the original problem object passed to the
+routine \verb|glp_intopt| or to the root subproblem on generating
+``lazy'' or/and cutting plane constraints.)\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int origin}}\\
+&The row origin flag:\\
+&\verb|GLP_RF_REG |---regular constraint;\\
+&\verb|GLP_RF_LAZY|---``lazy'' constraint;\\
+&\verb|GLP_RF_CUT |---cutting plane constraint.\\
+\end{tabular}
+
+\medskip
+
+\noindent\begin{tabular}{@{}p{17pt}@{}p{120.5mm}@{}}
+\multicolumn{2}{@{}l}{{\tt int klass}}\\
+&The row class descriptor, which is a number passed to the routine
+\verb|glp_ios_add_row| as its third parameter. If the row is a cutting
+plane constraint generated by the solver, its class may be the
+following:\\
+&\verb|GLP_RF_GMI |---Gomory's mixed integer cut;\\
+&\verb|GLP_RF_MIR |---mixed integer rounding cut;\\
+&\verb|GLP_RF_COV |---mixed cover cut;\\
+&\verb|GLP_RF_CLQ |---clique cut.\\
+\end{tabular}
+
+\newpage
+
+\subsection{glp\_ios\_mip\_gap---compute relative MIP gap}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_ios_mip_gap(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_mip_gap| computes the relative MIP gap (also
+called {\it duality gap}) with the following formula:
+$${\tt gap} = \frac{|{\tt best\_mip} - {\tt best\_bnd}|}
+{|{\tt best\_mip}| + {\tt DBL\_EPSILON}}$$
+where \verb|best_mip| is the best integer feasible solution found so
+far, \verb|best_bnd| is the best (global) bound. If no integer feasible
+solution has been found yet, \verb|gap| is set to \verb|DBL_MAX|.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_mip_gap| returns the relative MIP gap.
+
+\subsubsection*{Comments}
+
+The relative MIP gap is used to measure the quality of the best integer
+feasible solution found so far, because the optimal solution value
+$z^*$ for the original MIP problem always lies in the range
+$${\tt best\_bnd}\leq z^*\leq{\tt best\_mip}$$
+in case of minimization, or in the range
+$${\tt best\_mip}\leq z^*\leq{\tt best\_bnd}$$
+in case of maximization.
+
+To express the relative MIP gap in percents the value returned by the
+routine \verb|glp_ios_mip_gap| should be multiplied by 100\%.
+
+\newpage
+
+\subsection{glp\_ios\_node\_data---access application-specific data}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void *glp_ios_node_data(glp_tree *tree, int p);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_node_data| allows the application accessing a
+memory block allocated for the subproblem (which may be active or
+inactive), whose reference number is $p$.
+
+The size of the block is defined by the control parameter \verb|cb_size|
+passed to the routine \verb|glp_intopt|. The block is initialized by
+binary zeros on creating corresponding subproblem, and its contents is
+kept until the subproblem will be removed from the tree.
+
+The application may use these memory blocks to store specific data for
+each subproblem.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_node_data| returns a pointer to the memory
+block for the specified subproblem. Note that if \verb|cb_size| = 0, the
+routine returns a null pointer.
+
+\subsection{glp\_ios\_select\_node---select subproblem to continue the
+search}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ios_select_node(glp_tree *tree, int p);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_select_node| can be called from the
+user-defined callback routine in response to the reason
+\verb|GLP_ISELECT| to select an active subproblem, whose reference
+number is $p$. The search will be continued from the subproblem
+selected.
+
+\newpage
+
+\subsection{glp\_ios\_heur\_sol---provide solution found by heuristic}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_heur_sol(glp_tree *tree, const double x[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_heur_sol| can be called from the user-defined
+callback routine in response to the reason \verb|GLP_IHEUR| to provide
+an integer feasible solution found by a primal heuristic.
+
+Primal values of {\it all} variables (columns) found by the heuristic
+should be placed in locations $x[1]$, \dots, $x[n]$, where $n$ is the
+number of columns in the original problem object. Note that the routine
+\verb|glp_ios_heur_sol| does {\it not} check primal feasibility of the
+solution provided.
+
+Using the solution passed in the array $x$ the routine computes value
+of the objective function. If the objective value is better than the
+best known integer feasible solution, the routine computes values of
+auxiliary variables (rows) and stores all solution components in the
+problem object.
+
+\subsubsection*{Returns}
+
+If the provided solution is accepted, the routine
+\verb|glp_ios_heur_sol| returns zero. Otherwise, if the provided
+solution is rejected, the routine returns non-zero.
+
+\subsection{glp\_ios\_can\_branch---check if can branch upon specified
+variable}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_can_branch(glp_tree *tree, int j);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+If $j$-th variable (column) can be used to branch upon, the routine
+returns non-zero, otherwise zero.
+
+\newpage
+
+\subsection{glp\_ios\_branch\_upon---choose variable to branch upon}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_branch_upon| can be called from the
+user-defined callback routine in response to the reason
+\verb|GLP_IBRANCH| to choose a branching variable, whose ordinal number
+is $j$. Should note that only variables, for which the routine
+\verb|glp_ios_can_branch| returns non-zero, can be used to branch upon.
+
+The parameter \verb|sel| is a flag that indicates which branch
+(subproblem) should be selected next to continue the search:
+
+\verb|GLP_DN_BRNCH|---select down-branch;
+
+\verb|GLP_UP_BRNCH|---select up-branch;
+
+\verb|GLP_NO_BRNCH|---use general selection technique.
+
+\subsubsection*{Comments}
+
+On branching the solver removes the current active subproblem from the
+active list and creates two new subproblems ({\it down-} and {\it
+up-branches}), which are added to the end of the active list. Note that
+the down-branch is created before the up-branch, so the last active
+subproblem will be the up-branch.
+
+The down- and up-branches are identical to the current subproblem with
+exception that in the down-branch the upper bound of $x_j$, the variable
+chosen to branch upon, is replaced by $\lfloor x_j^*\rfloor$, while in
+the up-branch the lower bound of $x_j$ is replaced by
+$\lceil x_j^*\rceil$, where $x_j^*$ is the value of $x_j$ in optimal
+solution to LP relaxation of the current subproblem. For example, if
+$x_j^*=3.14$, the new upper bound of $x_j$ in the down-branch is
+$\lfloor 3.14\rfloor=3$, and the new lower bound in the up-branch is
+$\lceil 3.14\rceil=4$.)
+
+Additionally the callback routine may select either down- or up-branch,
+from which the solver will continue the search. If none of the branches
+is selected, a general selection technique will be used.
+
+\newpage
+
+\subsection{glp\_ios\_terminate---terminate the solution process}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ios_terminate(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_terminate| sets a flag indicating that the
+MIP solver should prematurely terminate the search.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{The search tree exploring routines}
+
+\subsection{glp\_ios\_tree\_size---determine size of the search tree}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
+      int *t_cnt);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_tree_size| stores the following three counts
+which characterize the current size of the search tree:
+
+\verb|a_cnt| is the current number of active nodes, i.e. the current
+size of the active list;
+
+\verb|n_cnt| is the current number of all (active and inactive) nodes;
+
+\verb|t_cnt| is the total number of nodes including those which have
+been already removed from the tree. This count is increased whenever
+a new node appears in the tree and never decreased.
+
+If some of the parameters \verb|a_cnt|, \verb|n_cnt|, \verb|t_cnt| is
+a null pointer, the corresponding count is not stored.
+
+\subsection{glp\_ios\_curr\_node---determine current active subprob-\\
+lem}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_curr_node(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_curr_node| returns the reference number of the
+current active subproblem. However, if the current subproblem does not
+exist, the routine returns zero.
+
+\newpage
+
+\subsection{glp\_ios\_next\_node---determine next active subproblem}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_next_node(glp_tree *tree, int p);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+If the parameter $p$ is zero, the routine \verb|glp_ios_next_node|
+returns the reference number of the first active subproblem. However,
+if the tree is empty, zero is returned.
+
+If the parameter $p$ is not zero, it must specify the reference number
+of some active subproblem, in which case the routine returns the
+reference number of the next active subproblem. However, if there is
+no next active subproblem in the list, zero is returned.
+
+All subproblems in the active list are ordered chronologically, i.e.
+subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
+
+\subsection{glp\_ios\_prev\_node---determine previous active subproblem}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_prev_node(glp_tree *tree, int p);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+If the parameter $p$ is zero, the routine \verb|glp_ios_prev_node|
+returns the reference number of the last active subproblem. However, if
+the tree is empty, zero is returned.
+
+If the parameter $p$ is not zero, it must specify the reference number
+of some active subproblem, in which case the routine returns the
+reference number of the previous active subproblem. However, if there
+is no previous active subproblem in the list, zero is returned.
+
+All subproblems in the active list are ordered chronologically, i.e.
+subproblem $A$ precedes subproblem $B$ if $A$ was created before $B$.
+
+\newpage
+
+\subsection{glp\_ios\_up\_node---determine parent subproblem}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_up_node(glp_tree *tree, int p);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The parameter $p$ must specify the reference number of some (active or
+inactive) subproblem, in which case the routine \verb|iet_get_up_node|
+returns the reference number of its parent subproblem. However, if the
+specified subproblem is the root of the tree and, therefore, has
+no parent, the routine returns zero.
+
+\subsection{glp\_ios\_node\_level---determine subproblem level}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_node_level(glp_tree *tree, int p);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_node_level| returns the level of the
+subproblem,\linebreak whose reference number is $p$, in the
+branch-and-bound tree. (The root subproblem has level 0, and the level
+of any other subproblem is the level of its parent plus one.)
+
+\subsection{glp\_ios\_node\_bound---determine subproblem local\\bound}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_ios_node_bound(glp_tree *tree, int p);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_node_bound| returns the local bound for
+(active or inactive) subproblem, whose reference number is $p$.
+
+\subsubsection*{Comments}
+
+The local bound for subproblem $p$ is an lower (minimization) or upper
+(maximization) bound for integer optimal solution to {\it this}
+subproblem (not to the original problem). This bound is local in the
+sense that only subproblems in the subtree rooted at node $p$ cannot
+have better integer feasible solutions.
+
+On creating a subproblem (due to the branching step) its local bound is
+inherited from its parent and then may get only stronger (never weaker).
+For the root subproblem its local bound is initially set to
+\verb|-DBL_MAX| (minimization) or \verb|+DBL_MAX| (maximization) and
+then improved as the root LP relaxation has been solved.
+
+Note that the local bound is not necessarily the optimal objective value
+to corresponding LP relaxation.
+
+\subsection{glp\_ios\_best\_node---find active subproblem with best
+local bound}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_best_node(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_best_node| returns the reference number of
+the active subproblem, whose local bound is best (i.e. smallest in case
+of minimization or largest in case of maximization). However, if the
+tree is empty, the routine returns zero.
+
+\subsubsection*{Comments}
+
+The best local bound is an lower (minimization) or upper (maximization)
+bound for integer optimal solution to the original MIP problem.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{The cut pool routines}
+
+\subsection{glp\_ios\_pool\_size---determine current size of the cut\\
+pool}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_pool_size(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_pool_size| returns the current size of the
+cut pool, that is, the number of cutting plane constraints currently
+added to it.
+
+\subsection{glp\_ios\_add\_row---add constraint to the cut pool}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_ios_add_row(glp_tree *tree, const char *name,
+      int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_add_row| adds specified row (cutting plane
+constraint) to the cut pool.
+
+The cutting plane constraint should have the following format:
+$$\sum_{j\in J}a_jx_j\left\{\begin{array}{@{}c@{}}\geq\\\leq\\
+\end{array}\right\}b,$$
+where $J$ is a set of indices (ordinal numbers) of structural variables,
+$a_j$ are constraint coefficients, $x_j$ are structural variables, $b$
+is the right-hand side.
+
+The parameter \verb|name| specifies a symbolic name assigned to the
+constraint (1 up to 255 characters). If it is \verb|NULL| or an empty
+string, no name is assigned.
+
+The parameter \verb|klass| specifies the constraint class, which must
+be either zero or a number in the range from 101 to 200. The application
+may use this attribute to distinguish between cutting plane constraints
+of different classes.\footnote{Constraint classes numbered from 1 to 100
+are reserved for GLPK cutting plane generators.}
+
+The parameter \verb|flags| currently is not used and must be zero.
+
+Ordinal numbers of structural variables (i.e. column indices) $j\in J$
+and numerical values of corresponding constraint coefficients $a_j$ must
+be placed in locations \verb|ind[1]|, \dots, \verb|ind[len]| and
+\verb|val[1]|, \dots, \verb|val[len]|, respectively, where
+${\tt len}=|J|$ is the number of constraint coefficients,
+$0\leq{\tt len}\leq n$, and $n$ is the number of columns in the problem
+object. Coefficients with identical column indices are not allowed.
+Zero coefficients are allowed, however, they are ignored.
+
+The parameter \verb|type| specifies the constraint type as follows:
+
+\verb|GLP_LO| means inequality constraint $\Sigma a_jx_j\geq b$;
+
+\verb|GLP_UP| means inequality constraint $\Sigma a_jx_j\leq b$;
+
+The parameter \verb|rhs| specifies the right-hand side $b$.
+
+All cutting plane constraints in the cut pool are identified by their
+ordinal numbers 1, 2, \dots, $size$, where $size$ is the current size
+of the cut pool. New constraints are always added to the end of the cut
+pool, thus, ordinal numbers of previously added constraints are not
+changed.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_ios_add_row| returns the ordinal number of the
+cutting plane constraint added, which is the new size of the cut pool.
+
+\subsubsection*{Example}
+
+\begin{verbatim}
+/* generate triangle cutting plane:
+   x[i] + x[j] + x[k] <= 1 */
+. . .
+/* add the constraint to the cut pool */
+ind[1] = i, val[1] = 1.0;
+ind[2] = j, val[2] = 1.0;
+ind[3] = k, val[3] = 1.0;
+glp_ios_add_row(tree, NULL, TRIANGLE_CUT, 0, 3, ind, val,
+                GLP_UP, 1.0);
+\end{verbatim}
+
+\subsubsection*{Comments}
+
+Cutting plane constraints added to the cut pool are intended to be then
+added only to the {\it current} subproblem, so these constraints can be
+globally as well as locally valid. However, adding a constraint to the
+cut pool does not mean that it will be added to the current
+subproblem---it depends on the solver's decision: if the constraint
+seems to be efficient, it is moved from the pool to the current
+subproblem, otherwise it is simply dropped.\footnote{Globally valid
+constraints could be saved and then re-used for other subproblems, but
+currently such feature is not implemented.}
+
+Normally, every time the callback routine is called for cut generation,
+the cut pool is empty. On the other hand, the solver itself can generate
+cutting plane constraints (like Gomory's or mixed integer rounding
+cuts), in which case the cut pool may be non-empty.
+
+\subsection{glp\_ios\_del\_row---remove constraint from the cut pool}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ios_del_row(glp_tree *tree, int i);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_del_row| deletes $i$-th row (cutting plane
+constraint) from the cut pool, where $1\leq i\leq size$ is the ordinal
+number of the constraint in the pool, $size$ is the current size of the
+cut pool.
+
+Note that deleting a constraint from the cut pool leads to changing
+ordinal numbers of other constraints remaining in the pool. New ordinal
+numbers of the remaining constraints are assigned under assumption that
+the original order of constraints is not changed. Let, for example,
+there be four constraints $a$, $b$, $c$ and $d$ in the cut pool, which
+have ordinal numbers 1, 2, 3 and 4, respectively, and let constraint
+$b$ have been deleted. Then after deletion the remaining constraint $a$,
+$c$ and $d$ are assigned new ordinal numbers 1, 2 and 3, respectively.
+
+To find the constraint to be deleted the routine \verb|glp_ios_del_row|
+uses ``smart'' linear search, so it is recommended to remove constraints
+in a natural or reverse order and avoid removing them in a random order.
+
+\subsubsection*{Example}
+
+\begin{verbatim}
+/* keep first 10 constraints in the cut pool and remove other
+   constraints */
+while (glp_ios_pool_size(tree) > 10)
+   glp_ios_del_row(tree, glp_ios_pool_size(tree));
+\end{verbatim}
+
+\newpage
+
+\subsection{glp\_ios\_clear\_pool---remove all constraints from the cut
+pool}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_ios_clear_pool(glp_tree *tree);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_ios_clear_pool| makes the cut pool empty deleting
+all existing rows (cutting plane constraints) from it.
+
+%* eof *%
Index: deps/glpk/doc/glpk06.tex
===================================================================
--- deps/glpk/doc/glpk06.tex	(revision 9)
+++ deps/glpk/doc/glpk06.tex	(revision 9)
@@ -0,0 +1,896 @@
+%* glpk06.tex *%
+
+\chapter{Miscellaneous API Routines}
+
+\section{GLPK environment routines}
+
+\subsection{glp\_long---64-bit integer data type}
+
+Some GLPK API routines use 64-bit integer data type, which is declared
+in the header \verb|glpk.h| as follows:
+
+\begin{verbatim}
+typedef struct { int lo, hi; } glp_long;
+\end{verbatim}
+
+\noindent
+where \verb|lo| contains low 32 bits, and \verb|hi| contains high 32
+bits of 64-bit integer value.\footnote{GLPK conforms to ILP32, LLP64,
+and LP64 programming models, where the built-in type {\tt int}
+corresponds to 32-bit integers.}
+
+\subsection{glp\_init\_env---initialize GLPK environment}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_init_env(void);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_init_env| initializes the GLPK environment.
+Normally the application program does not need to call this routine,
+because it is called automatically on the first call to any API routine.
+
+\newpage
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_init_env| returns one of the following codes:
+
+\noindent
+0 --- initialization successful;
+
+\noindent
+1 --- environment is already initialized;
+
+\noindent
+2 --- initialization failed (insufficient memory);
+
+\noindent
+3 --- initialization failed (unsupported programming model).
+
+\subsection{glp\_version---determine library version}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+const char *glp_version(void);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_version| returns a pointer to a null-terminated
+character string, which specifies the version of the GLPK library in
+the form \verb|"X.Y"|, where `\verb|X|' is the major version number, and
+`\verb|Y|' is the minor version number, for example, \verb|"4.16"|.
+
+\subsubsection*{Example}
+
+\begin{footnotesize}
+\begin{verbatim}
+printf("GLPK version is %s\n", glp_version());
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_free\_env---free GLPK environment}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_free_env(void);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_free_env| frees all resources used by GLPK
+routines (memory blocks, etc.) which are currently still in use.
+
+Normally the application program does not need to call this routine,
+because GLPK routines always free all unused resources. However, if
+the application program even has deleted all problem objects, there
+will be several memory blocks still allocated for the internal library
+needs. For some reasons the application program may want GLPK to free
+this memory, in which case it should call \verb|glp_free_env|.
+
+Note that a call to \verb|glp_free_env| invalidates all problem objects
+which still exist.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_free_env| returns one of the following codes:
+
+\noindent
+0 --- termination successful;
+
+\noindent
+1 --- environment is inactive (was not initialized).
+
+\subsection{glp\_printf---write formatted output to terminal}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_printf(const char *fmt, ...);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_printf| uses the format control string
+\verb|fmt| to format its parameters and writes the formatted output to
+the terminal.
+
+This routine is a replacement of the standard C function
+\verb|printf| and used by all GLPK routines to perform terminal
+output. The application program may use \verb|glp_printf| for the same
+purpose that allows controlling its terminal output with the routines
+\verb|glp_term_out| and \verb|glp_term_hook|.
+
+\subsection{glp\_vprintf---write formatted output to terminal}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_vprintf(const char *fmt, va_list arg);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_vprintf| uses the format control string
+\verb|fmt| to format its parameters specified by the list \verb|arg|
+and writes the formatted output to the terminal.
+
+This routine is a replacement of the standard C function
+\verb|vprintf| and used by all GLPK routines to perform terminal
+output. The application program may use \verb|glp_vprintf| for the same
+purpose that allows controlling its terminal output with the routines
+\verb|glp_term_out| and \verb|glp_term_hook|.
+
+\newpage
+
+\subsection{glp\_term\_out---enable/disable terminal output}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_term_out(int flag);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+Depending on the parameter flag the routine \verb|glp_term_out| enables
+or disables terminal output performed by glpk routines:
+
+\verb|GLP_ON | --- enable terminal output;
+
+\verb|GLP_OFF| --- disable terminal output.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_term_out| returns the previous value of the
+terminal output flag (\verb|GLP_ON| or \verb|GLP_OFF|).
+
+\subsection{glp\_term\_hook---intercept terminal output}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_term_hook(int (*func)(void *info, const char *s),
+      void *info);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_term_hook| installs the user-defined hook routine
+to intercept all terminal output performed by GLPK routines.
+
+%This feature can be used to redirect the terminal output to other
+%destination, for example, to a file or a text window.
+
+The parameter {\it func} specifies the user-defined hook routine. It is
+called from an internal printing routine, which passes to it two
+parameters: {\it info} and {\it s}. The parameter {\it info} is a
+transit pointer specified in corresponding call to the routine
+\verb|glp_term_hook|; it may be used to pass some additional information
+to the hook routine. The parameter {\it s} is a pointer to the null
+terminated character string, which is intended to be written to the
+terminal. If the hook routine returns zero, the printing routine writes
+the string {\it s} to the terminal in a usual way; otherwise, if the
+hook routine returns non-zero, no terminal output is performed.
+
+To uninstall the hook routine both parameters {\it func} and {\it info}
+should be specified as \verb|NULL|.
+
+\newpage
+
+\subsubsection*{Example}
+
+\begin{footnotesize}
+\begin{verbatim}
+static int hook(void *info, const char *s)
+{     FILE *foo = info;
+      fputs(s, foo);
+      return 1;
+}
+
+int main(void)
+{     FILE *foo;
+      . . .
+      /* redirect terminal output */
+      glp_term_hook(hook, foo);
+      . . .
+      /* resume terminal output */
+      glp_term_hook(NULL, NULL);
+      . . .
+}
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_open\_tee---start copying terminal output}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_open_tee(const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_open_tee| starts copying all the terminal output
+to an output text file, whose name is specified by the character string
+\verb|fname|.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_open_tee| returns one of the following codes:
+
+\noindent
+0 --- operation successful;
+
+\noindent
+1 --- copying terminal output is already active;
+
+\noindent
+2 --- unable to create output file.
+
+\newpage
+
+\subsection{glp\_close\_tee---stop copying terminal output}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_close_tee(void);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_close_tee| stops copying the terminal output to
+the output text file previously open by the routine \verb|glp_open_tee|
+closing that file.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_close_tee| returns one of the following codes:
+
+\noindent
+0 --- operation successful;
+
+\noindent
+1 --- copying terminal output was not started.
+
+\subsection{glp\_error---display error message and terminate execution}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_error(const char *fmt, ...);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_error| (implemented as a macro) formats its
+parameters using the format control string \verb|fmt|, writes the
+formatted message to the terminal, and then abnormally terminates the
+program.
+
+\subsection{glp\_assert---check logical condition}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_assert(int expr);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_assert| (implemented as a macro) checks
+a logical condition specified by the expression \verb|expr|. If the
+condition is true (non-zero), the routine does nothing; otherwise, if
+the condition is false (zero), the routine prints an error message and
+abnormally terminates the program.
+
+This routine is a replacement of the standard C function \verb|assert|
+and used by all GLPK routines to check program logic. The application
+program may use \verb|glp_assert| for the same purpose.
+
+\subsection{glp\_error\_hook---install hook to intercept abnormal
+termination}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_error_hook(void (*func)(void *info), void *info);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_error_hook| installs a user-defined hook routine
+to intercept abnormal termination.
+
+The parameter \verb|func| specifies the user-defined hook routine. It
+is called from the routine \verb|glp_error| before the latter calls the
+abort function to abnormally terminate the application program because
+of fatal error. The parameter \verb|info| is a transit pointer,
+specified in the corresponding call to the routine
+\verb|glp_error_hook|; it may be used to pass some information to the
+hook routine.
+
+To uninstall the hook routine the parameters \verb|func| and \verb|info|
+should be specified as \verb|NULL|.
+
+\subsubsection*{Usage note}
+
+If the hook routine returns, the application program is abnormally
+terminated. To prevent abnormal termnation the hook routine may perform
+a global jump using the standard function \verb|longjmp|, in which case
+the application program {\it must} call the routine \verb|glp_free_env|.
+
+\subsection{glp\_malloc---allocate memory block}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void *glp_malloc(int size);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_malloc| dynamically allocates a memory block of
+\verb|size| bytes long. Should note that:
+
+1) the parameter \verb|size| must be positive;
+
+2) being allocated the memory block contains arbitrary data, that is,
+it is {\it not} initialized by binary zeros;
+
+3) if the block cannot be allocated due to insufficient memory, the
+routine prints an error message and abnormally terminates the program.
+
+This routine is a replacement of the standard C function \verb|malloc|
+and used by all GLPK routines for dynamic memory allocation. The
+application program may use \verb|glp_malloc| for the same purpose.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_malloc| returns a pointer to the memory block
+allocated. To free this block the routine \verb|glp_free| (not the
+standard C function \verb|free|!) must be used.
+
+\subsection{glp\_calloc---allocate memory block}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void *glp_calloc(int n, int size);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_calloc| dynamically allocates a memory block of
+\verb|n|$\times$\verb|size| bytes long. Should note that:
+
+1) both parameters \verb|n| and \verb|size| must be positive;
+
+2) being allocated the memory block contains arbitrary data, that is,
+it is {\it not} initialized by binary zeros;
+
+3) if the block cannot be allocated due to insufficient memory, the
+routine prints an error message and abnormally terminates the program.
+
+This routine is a replacement of the standard C function \verb|calloc|
+(with exception that the block is not cleaned) and used by all GLPK
+routines for dynamic memory allocation. The application program may use
+\verb|glp_calloc| for the same purpose.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_calloc| returns a pointer to the memory block
+allocated. To free this block the routine \verb|glp_free| (not the
+standard C function \verb|free|!) must be used.
+
+\subsection{glp\_free---free memory block}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_free(void *ptr);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_free| frees (deallocates) a memory block pointed
+to by \verb|ptr|, which was previously allocated by the routine
+\verb|glp_malloc| or \verb|glp_calloc|. Note that the pointer \verb|ptr|
+must valid and must not be \verb|NULL|.
+
+This routine is a replacement of the standard C function \verb|free|
+and used by all GLPK routines for dynamic memory allocation. The
+application program may use \verb|glp_free| for the same purpose.
+
+\subsection{glp\_mem\_usage---get memory usage information}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_mem_usage(int *count, int *cpeak, glp_long *total,
+      glp_long *tpeak);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mem_usage| reports some information about
+utilization of the memory by the routines \verb|glp_malloc|,
+\verb|glp_calloc|, and \verb|glp_free|. Information is stored to
+locations specified by corresponding parameters (see below). Any
+parameter can be specified as \verb|NULL|, in which case corresponding
+information is not stored.
+
+\verb|*count| is the number of currently allocated memory blocks.
+
+\verb|*cpeak| is the peak value of \verb|*count| reached since the
+initialization of the GLPK library environment.
+
+\verb|*total| is the total amount, in bytes, of currently allocated
+memory blocks.
+
+\verb|*tpeak| is the peak value of \verb|*total| reached since the
+initialization of the GLPK library envirionment.
+
+\subsubsection*{Example}
+
+\begin{footnotesize}
+\begin{verbatim}
+glp_mem_usage(&count, NULL, NULL, NULL);
+printf("%d memory block(s) are still allocated\n", count);
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_mem\_limit---set memory usage limit}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_mem_limit(int limit);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mem_limit| limits the amount of memory available
+for dynamic allocation (with the routines \verb|glp_malloc| and
+\verb|glp_calloc|) to \verb|limit| megabytes.
+
+\subsection{glp\_time---determine current universal time}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+glp_long glp_time(void);
+\end{verbatim}
+
+\subsection*{Returns}
+
+The routine \verb|glp_time| returns the current universal time (UTC),
+in milliseconds, elapsed since 00:00:00 GMT January 1, 1970.
+
+\subsection{glp\_difftime---compute difference between two time values}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_difftime(glp_long t1, glp_long t0);
+\end{verbatim}
+
+\subsection*{Returns}
+
+The routine \verb|glp_difftime| returns the difference between two time
+values \verb|t1| and \verb|t0|, expressed in seconds.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Plain data file reading routines}
+
+\subsection{Introduction}
+
+On developing simple applications to solve optimization problems it is
+often needed to read data from plain text files. To do this the standard
+C function \verb|fscanf| may be used, however, it is not convenient; for
+example, if it scans an integer number according to the format
+specification `\verb|%d|', and that number is coded incorrectly,
+no diagnostics is provided.
+
+This section describes a set of GLPK API routines, which may be used in
+application programs to simplify reading data from plain text files.
+
+\subsubsection*{Example 1}
+
+The following main program reads ten integer numbers from plain text
+file \verb|data.txt| and prints their sum.
+
+\begin{footnotesize}
+\begin{verbatim}
+/* sdfsamp1.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_data *data;
+      int j, num, sum;
+      /* open plain data file */
+      data = glp_sdf_open_file("data.txt");
+      if (data == NULL) exit(EXIT_FAILURE);
+      sum = 0;
+      for (j = 1; j <= 10; j++)
+      {  /* read next integer number */
+         num = glp_sdf_read_int(data);
+         sum += num;
+      }
+      printf("sum = %d\n", sum);
+      /* close plain data file */
+      glp_sdf_close_file(data);
+      return 0;
+}
+
+/* eof */
+\end{verbatim}
+\end{footnotesize}
+
+The input data are coded in free format. For example, the file
+\verb|data.txt| may look like this:
+
+\begin{footnotesize}
+\begin{verbatim}
+123 65 432 890 -12 743 895 -7 111 326
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+or like this:
+
+\begin{footnotesize}
+\begin{verbatim}
+123   65  432  890  -12
+743  895   -7  111  326
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+If the input data file contains incorrect data, the routine
+\verb|glp_sdf_read_int| prints an error message and, if no error
+handling is provided by the application program, abnormally terminates
+program execution. For example, the file \verb|data.txt| could contain
+the following data:
+
+\begin{footnotesize}
+\begin{verbatim}
+123   65  432  890  -12
+743  895   =7  111  326
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+in which case the error message would be the following:
+
+\begin{footnotesize}
+\begin{verbatim}
+data.txt:2: cannot convert `=7' to integer
+\end{verbatim}
+\end{footnotesize}
+
+\subsubsection*{Example 2}
+
+As it was said above, by default any attempt to read incorrect data
+leads to abnormal termination. However, sometimes it is desirable to
+catch such errors. This feature is illustrated by the following main
+program, which does the same job as in the previous example.
+
+\begin{footnotesize}
+\begin{verbatim}
+/* sdfsamp2.c */
+
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_data *data;
+      jmp_buf jump;
+      int j, num, sum, ret;
+      /* open plain data file */
+      data = glp_sdf_open_file("data.txt");
+      if (data == NULL)
+      {  ret = EXIT_FAILURE;
+         goto done;
+      }
+      /* set up error handling */
+      if (setjmp(jump))
+      {  ret = EXIT_FAILURE;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      /* read and process data */
+      sum = 0;
+      for (j = 1; j <= 10; j++)
+      {  /* read next integer number */
+         num = glp_sdf_read_int(data);
+         if (abs(num) > 1000)
+            glp_sdf_error(data, "integer %d too big\n", num);
+         if (num < 0)
+            glp_sdf_warning(data, "integer %d is negative\n", num);
+         sum += num;
+      }
+      printf("sum = %d\n", sum);
+      ret = EXIT_SUCCESS;
+done: /* close plain data file */
+      if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/* eof */
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_sdf\_open\_file---open plain data file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+glp_data *glp_sdf_open_file(const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_open_file| opens a plain data file, whose
+name is specified by the character string \verb|fname|.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine \verb|glp_sdf_open_file|
+returns a pointer to the opaque program object of the type
+\verb|glp_data|\footnote{This data structure is declared in the header
+file {\tt glpk.h}.} associated with the plain data file. Otherwise, if
+the operation failed, the routine prints an error message and returns
+\verb|NULL|.
+
+\subsubsection*{Note}
+
+The application program should use the pointer returned by the routine
+\verb|glp_sdf_open_file| to perform all subsequent operations on the
+data file.
+
+\newpage
+
+\subsection{glp\_sdf\_set\_jump---set up error handling}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_sdf_set_jump(glp_data *data, jmp_buf jump);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_set_jump| sets up error handling for the
+plain data file specified by the parameter \verb|data|.
+
+The parameter \verb|jump| specifies the environment buffer, which must
+be initialized with the standard C function \verb|setjmp| prior to call
+to the routine \verb|glp_sdf_set_jump|. Detecting any incorrect data in
+the corresponding plain data file will cause non-local ``go to'' by
+a call to the standard C function \verb|longjmp|.
+
+The parameter \verb|jump| can be specified as \verb|NULL|, in which
+case the routine \verb|glp_sdf_set_jump| restores the default behavior,
+in which case detecting incorrect data leads to abnormal termination.
+
+\subsection{glp\_sdf\_error---print error message}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_sdf_error(glp_data *data, const char *fmt, ...);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_error| prints an error message related to the
+plain data file specified by the parameter \verb|data|. If error handing
+was not previously provided, the routine then abnormally terminates
+execution of the application program. Otherwise, it signals about the
+error by a call to the standard C function \verb|longjmp|.
+
+The character string \verb|fmt| and optional parameters following it
+have the same meaning as for the standard C function \verb|printf|.
+
+The message produced by the routine \verb|glp_sdf_error| looks like
+follows:
+
+\medskip
+
+{\it file}{\tt :}{\it line}{\tt :} {\it message text}
+
+\medskip
+
+\noindent
+where {\it file} is the filename passed to the routine
+\verb|glp_sdf_open| and {\it line} is the current line number.
+
+\newpage
+
+\subsection{glp\_sdf\_warning---print warning message}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_sdf_warning(glp_data *data, const char *fmt, ...);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_warning| prints a warning message related to
+the plain data file specified by the parameter \verb|data|.
+
+The character string \verb|fmt| and optional parameters following it
+have the same meaning as for the standard C function \verb|printf|.
+
+The message produced by the routine \verb|glp_sdf_warning| looks like
+follows:
+
+\medskip
+
+{\it file}{\tt :}{\it line}\verb|: warning:| {\it message text}
+
+\medskip
+
+\noindent
+where {\it file} is the filename passed to the routine
+\verb|glp_sdf_open| and {\it line} is the current line number.
+
+\subsection{glp\_sdf\_read\_int---read integer number}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_sdf_read_int(glp_data *data);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_read_int| skips optional white-space
+characters and then reads an integer number from the plain data file
+specified by the parameter \verb|data|. If the operation failed, the
+routine \verb|glp_sdf_read_int| calls the routine \verb|glp_sdf_error|
+(see above).
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_sdf_read_int| returns the integer number read.
+
+\newpage
+
+\subsection{glp\_sdf\_read\_num---read floating-point number}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+double glp_sdf_read_num(glp_data *data);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_read_num| skips optional white-space
+characters and then reads a floating-point number from the plain data
+file specified by the parameter \verb|data|. If the operation failed,
+the routine \verb|glp_sdf_num| calls the routine \verb|glp_sdf_error|
+(see above).
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_sdf_read_num| returns the floating-point number
+read.
+
+\subsection{glp\_sdf\_read\_item---read data item}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+const char *glp_sdf_read_item(glp_data *data);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_read_item| skips optional white-space
+characters and then reads a data item from the plain data file specified
+by the parameter \verb|data|. If the operation failed, the routine
+\verb|glp_sdf_read_item| calls the routine \verb|glp_sdf_error| (see
+above).
+
+{\it Data item} is a sequence of 1 to 255 arbitrary graphic characters
+delimited by white-space characters. Data items may be used to represent
+symbolic names, identifiers, etc.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_sdf_read_item| returns a pointer to the internal
+buffer, which contains the data item read in the form of a
+null-terminated character string.
+
+\newpage
+
+\subsection{glp\_sdf\_read\_text---read text until end of line}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+const char *glp_sdf_read_text(glp_data *data);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_read_text| reads a text from the plain data
+file specified by the parameter \verb|data|.
+
+Reading starts from the current position and extends until end of the
+current line. Initial and trailing white-space characters as well as
+the newline character are not included in the text.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_sdf_read_text| returns a pointer to the internal
+buffer, which contains the text read in the form of a null-terminated
+character string.
+
+\subsection{glp\_sdf\_line---determine current line number}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_sdf_line(glp_data *data);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_sdf_line| returns the current line number for the
+plain data file specified by the parameter \verb|data|.
+
+\subsection{glp\_sdf\_close\_file---close plain data file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_sdf_close_file(glp_data *data);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_sdf_close_file| closes the plain data file
+specified by the parameter \verb|data| and frees all the resources
+allocated to this program object.
+
+%* eof *%
Index: deps/glpk/doc/glpk07.tex
===================================================================
--- deps/glpk/doc/glpk07.tex	(revision 9)
+++ deps/glpk/doc/glpk07.tex	(revision 9)
@@ -0,0 +1,336 @@
+%* glpk07.tex *%
+
+\chapter{Installing GLPK on Your Computer}
+\label{install}
+
+\section{Downloading the distribution tarball}
+
+The distribution tarball of the most recent version of the GLPK
+package can be found on \url{http://ftp.gnu.org/gnu/glpk/} [via http]
+and \url{ftp://ftp.gnu.org/gnu/glpk/} [via FTP]. It can also be found
+on one of the FTP mirrors; see \url{http://www.gnu.org/prep/ftp.html}.
+Please use a mirror if possible.
+
+To make sure that the GLPK distribution tarball you have downloaded is
+intact you need to download the corresponding `\verb|.sig|' file and
+run a command like this:
+
+\begin{verbatim}
+   gpg --verify glpk-4.38.tar.gz.sig
+\end{verbatim}
+
+\noindent
+If that command fails because you do not have the required public key,
+run the following command to import it:
+
+\begin{verbatim}
+   gpg --keyserver keys.gnupg.net --recv-keys 5981E818
+\end{verbatim}
+
+\noindent
+and then re-run the previous command.
+
+\section{Unpacking the distribution tarball}
+
+The GLPK package (like all other GNU software) is distributed in the
+form of packed archive. This is one file named \verb|glpk-X.Y.tar.gz|,
+where {\it X} is the major version number and {\it Y} is the minor
+version number.
+
+In order to prepare the distribution for installation you should:
+
+\medskip
+
+1. Copy the GLPK distribution file to a working subdirectory.
+
+\medskip
+
+2. Unpack the distribution file with the following command:
+
+\begin{verbatim}
+   gzip -d glpk-X.Y.tar.gz
+\end{verbatim}
+
+\noindent
+that renames the distribution file to \verb|glpk-X.Y.tar|.
+
+\medskip
+
+3. Unarchive the distribution file with the following command:
+
+\begin{verbatim}
+   tar -x < glpk-X.Y.tar
+\end{verbatim}
+
+\noindent
+that automatically creates the subdirectory \verb|glpk-X.Y| containing
+the GLPK distribution.
+
+
+\section{Configuring the package}
+
+After unpacking and unarchiving the GLPK distribution you should
+configure the package, i.e. automatically tune it for your platform.
+
+Normally, you should just \verb|cd| to the subdirectory
+\verb|glpk-X.Y| and run the configure script, e.g.
+
+\begin{verbatim}
+   ./configure
+\end{verbatim}
+
+The `\verb|configure|' shell script attempts to guess correct values
+for various system-dependent variables used during compilation. It uses
+those values to create a `\verb|Makefile|' in each directory of the
+package. It also creates file `\verb|config.h|' containing
+platform-dependent definitions. Finally, it creates a shell script
+`\verb|config.status|' that you can run in the future to recreate the
+current configuration, a file `\verb|config.cache|' that saves the
+results of its tests to speed up reconfiguring, and a file
+`\verb|config.log|' containing compiler output (useful mainly for
+debugging `\verb|configure|').
+
+Running `\verb|configure|' takes about a few minutes. While it is
+running, it displays some informational messages that tell you what it
+is doing. If you don't want to see these messages, run
+`\verb|configure|' with its standard output redirected to
+`\verb|dev/null|'; for example, `\verb|./configure > /dev/null|'.
+
+By default both static and shared versions of the GLPK library will be
+compiled. Compilation of the shared librariy can be turned off by
+specifying the `\verb|--disable-shared|' option to `\verb|configure|',
+e.g.
+
+\begin{verbatim}
+   ./configure --disable-shared
+\end{verbatim}
+
+\noindent
+If you encounter problems building the library try using the above
+option, because some platforms do not support shared libraries.
+
+\newpage
+
+The GLPK package has some optional features listed below. By default
+all these features are disabled. To enable a feature the corresponding
+option should be passed to the configure script.
+
+\bigskip
+
+\noindent
+\verb|--with-gmp         | Enable using the GNU MP bignum library
+
+\medskip
+
+This feature allows the exact simplex solver to use the GNU MP bignum
+library. If it is disabled, the exact simplex solver uses the GLPK
+bignum module, which provides the same functionality as GNU MP, however,
+it is much less efficient.
+
+For details about the GNU MP bignum library see its web page at
+\url{http://gmplib.org/}.
+
+\bigskip
+
+\noindent
+\verb|--with-zlib        |
+Enable using the zlib data compression library
+
+\medskip
+
+This feature allows GLPK API routines and the stand-alone solver to
+read and write compressed data files performing compression and
+decompression ``on the fly'' (compressed data files are recognized by
+suffix `\verb|.gz|' in the file name). It may be useful in case of
+large MPS files to save the disk space.
+
+For details about the zlib compression library see its web page at
+\url{http://www.zlib.net/}.
+
+\bigskip
+
+\noindent
+\verb|--enable-dl        | The same as `\verb|--enable-dl=ltdl|'
+
+\noindent
+\verb|--enable-dl=ltdl   | Enable shared library support (GNU)
+
+\noindent
+\verb|--enable-dl=dlfcn  | Enable shared library support (POSIX)
+
+\medskip
+
+Currently this feature is only needed to provide dynamic linking to
+ODBC and MySQL shared libraries (see below).
+
+For details about the GNU shared library support see the manual at
+\url{http://www.gnu.org/software/libtool/manual/}.
+
+\bigskip
+
+\noindent
+\verb|--enable-odbc      |
+Enable using ODBC table driver (\verb|libiodbc|)
+
+\noindent
+\verb|--enable-odbc=unix |
+Enable using ODBC table driver (\verb|libodbc|)
+
+\medskip
+
+This feature allows transmitting data between MathProg model objects
+and relational databases accessed through ODBC.
+
+For more details about this feature see the supplement ``Using Data
+Tables in the GNU MathProg Modeling Language'' (\verb|doc/tables.pdf|).
+
+\bigskip
+
+\noindent
+\verb|--enable-mysql     |
+Enable using MySQL table driver (\verb|libmysql|)
+
+\medskip
+
+This feature allows transmitting data between MathProg model objects
+and MySQL relational databases.
+
+For more details about this feature see the supplement ``Using Data
+Tables in the GNU MathProg Modeling Language'' (\verb|doc/tables.pdf|).
+
+\section{Compiling the package}
+
+Normally, you can compile (build) the package by typing the command:
+
+\begin{verbatim}
+   make
+\end{verbatim}
+
+\noindent
+It reads `\verb|Makefile|' generated by `\verb|configure|' and performs
+all necessary jobs.
+
+If you want, you can override the `\verb|make|' variables \verb|CFLAGS|
+and \verb|LDFLAGS| like this:
+
+\begin{verbatim}
+   make CFLAGS=-O2 LDFLAGS=-s
+\end{verbatim}
+
+To compile the package in a different directory from the one containing
+the source code, you must use a version of `\verb|make|' that supports
+`\verb|VPATH|' variable, such as GNU `\verb|make|'. `\verb|cd|' to the
+directory where you want the object files and executables to go and run
+the `\verb|configure|' script. `\verb|configure|' automatically checks
+for the source code in the directory that `\verb|configure|' is in and
+in `\verb|..|'. If for some reason `\verb|configure|' is not in the
+source code directory that you are configuring, then it will report that
+it can't find the source code. In that case, run `\verb|configure|' with
+the option `\verb|--srcdir=DIR|', where \verb|DIR| is the directory that
+contains the source code.
+
+Some systems require unusual options for compilation or linking that
+the `\verb|configure|' script does not know about. You can give
+`\verb|configure|' initial values for variables by setting them in the
+environment. Using a Bourne-compatible shell, you can do that on the
+command line like this:
+
+\begin{verbatim}
+   CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+\end{verbatim}
+
+\noindent
+Or on systems that have the `\verb|env|' program, you can do it like
+this:
+
+\begin{verbatim}
+   env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+\end{verbatim}
+
+Here are the `\verb|make|' variables that you might want to override
+with environment variables when running `\verb|configure|'.
+
+For these variables, any value given in the environment overrides the
+value that `\verb|configure|' would choose:
+
+\medskip
+
+\noindent
+\verb|CC      | C compiler program. The default is `\verb|cc|'.
+
+\medskip
+
+\noindent
+\verb|INSTALL | Program used to install files. The default value is
+`\verb|install|' if
+
+\noindent
+\verb|        | you have it, otherwise `\verb|cp|'.
+
+\medskip
+
+For these variables, any value given in the environment is added to the
+value that `\verb|configure|' chooses:
+
+\medskip
+
+\noindent
+\verb|DEFS    | Configuration options, in the form
+`\verb|-Dfoo -Dbar| \dots'.
+
+\medskip
+
+\noindent
+\verb|LIBS    | Libraries to link with, in the form
+`\verb|-lfoo -lbar| \dots'.
+
+\section{Checking the package}
+
+To check the package, i.e. to run some tests included in the package,
+you can use the following command:
+
+\begin{verbatim}
+   make check
+\end{verbatim}
+
+\section{Installing the package}
+
+Normally, to install the GLPK package you should type the following
+command:
+
+\begin{verbatim}
+   make install
+\end{verbatim}
+
+\noindent
+By default, `\verb|make install|' will install the package's files in
+`\verb|usr/local/bin|', `\verb|usr/local/lib|', etc. You can specify an
+installation prefix other than `\verb|/usr/local|' by giving
+`\verb|configure|' the option `\verb|--prefix=PATH|'. Alternately, you
+can do so by consistently giving a value for the `\verb|prefix|'
+variable when you run `\verb|make|', e.g.
+
+\begin{verbatim}
+   make prefix=/usr/gnu
+   make prefix=/usr/gnu install
+\end{verbatim}
+
+After installing you can remove the program binaries and object files
+from the source directory by typing `\verb|make clean|'. To remove all
+files that `\verb|configure|' created (`\verb|Makefile|',
+`\verb|config.status|', etc.), just type `\verb|make distclean|'.
+
+The file `\verb|configure.ac|' is used to create `\verb|configure|' by
+a program called `\verb|autoconf|'. You only need it if you want to
+remake `\verb|configure|' using a newer version of `\verb|autoconf|'.
+
+\section{Uninstalling the package}
+
+To uninstall the GLPK package, i.e. to remove all the package's files
+from the system places, you can use the following command:
+
+\begin{verbatim}
+   make uninstall
+\end{verbatim}
+
+%* eof *%
Index: deps/glpk/doc/glpk08.tex
===================================================================
--- deps/glpk/doc/glpk08.tex	(revision 9)
+++ deps/glpk/doc/glpk08.tex	(revision 9)
@@ -0,0 +1,696 @@
+%* glpk08.tex *%
+
+\chapter{MPS Format}
+\label{champs}
+
+\section{Fixed MPS Format}
+\label{secmps}
+
+The MPS format\footnote{The MPS format was developed in 1960's by IBM
+as input format for their mathematical programming system MPS/360.
+Today the MPS format is a most widely used format understood by most
+mathematical programming packages. This appendix describes only the
+features of the MPS format, which are implemented in the GLPK package.}
+is intended for coding LP/MIP problem data. This format assumes the
+formulation of LP/MIP problem (1.1)---(1.3) (see Section \ref{seclp},
+page \pageref{seclp}).
+
+{\it MPS file} is a text file, which contains two types of
+cards\footnote{In 1960's MPS file was a deck of 80-column punched cards,
+so the author decided to keep the word ``card'', which may be understood
+as ``line of text file''.}: indicator cards and data cards.
+
+Indicator cards determine a kind of succeeding data. Each indicator card
+has one word in uppercase letters beginning in column 1.
+
+Data cards contain problem data. Each data card is divided into six
+fixed fields:
+
+\begin{center}
+\begin{tabular}{lcccccc}
+& Field 1 & Field 2 & Field 3 & Field 4 & Field 5 & Feld 6 \\
+\hline
+Columns & 2---3 & 5---12 & 15---22 & 25---36 & 40---47 & 50---61 \\
+Contents & Code & Name & Name & Number & Name & Number \\
+\end{tabular}
+\end{center}
+
+On a particular data card some fields may be optional.
+
+Names are used to identify rows, columns, and some vectors (see below).
+
+Aligning the indicator code in the field 1 to the left margin is
+optional.
+
+All names specified in the fields 2, 3, and 5 should contain from 1 up
+to 8 arbitrary characters (except control characters). If a name is
+placed in the field 3 or 5, its first character should not be the dollar
+sign `\verb|$|'. If a name contains spaces, the spaces are ignored.
+
+All numerical values in the fields 4 and 6 should be coded in the form
+$sxx$\verb|E|$syy$, where $s$ is the plus `\verb|+|' or the minus
+`\verb|-|' sign, $xx$ is a real number with optional decimal point,
+$yy$ is an integer decimal exponent. Any number should contain up to 12
+characters. If the sign $s$ is omitted, the plus sign is assumed. The
+exponent part is optional. If a number contains spaces, the spaces are
+ignored.
+
+If a card has the asterisk `\verb|*|' in the column 1, this card is
+considered as a comment and ignored. Besides, if the first character in
+the field 3 or 5 is the dollar sign `\verb|$|', all characters from the
+dollar sign to the end of card are considered as a comment and ignored.
+
+MPS file should contain cards in the following order:
+
+$\bullet$ NAME indicator card;
+
+$\bullet$ ROWS indicator card;
+
+$\bullet$ data cards specifying rows (constraints);
+
+$\bullet$ COLUMNS indicator card;
+
+$\bullet$ data cards specifying columns (structural variables) and
+constraint coefficients;
+
+$\bullet$ RHS indicator card;
+
+$\bullet$ data cards specifying right-hand sides of constraints;
+
+$\bullet$ RANGES indicator card;
+
+$\bullet$ data cards specifying ranges for double-bounded constraints;
+
+$\bullet$ BOUNDS indicator card;
+
+$\bullet$ data cards specifying types and bounds of structural
+variables;
+
+$\bullet$ ENDATA indicator card.
+
+{\it Section} is a group of cards consisting of an indicator card and
+data cards succeeding this indicator card. For example, the ROWS section
+consists of the ROWS indicator card and data cards specifying rows.
+
+The sections RHS, RANGES, and BOUNDS are optional and may be omitted.
+
+\section{Free MPS Format}
+
+{\it Free MPS format} is an improved version of the standard (fixed)
+MPS format described above.\footnote{This format was developed in the
+beginning of 1990's by IBM as an alternative to the standard fixed MPS
+format for Optimization Subroutine Library (OSL).} Note that all
+changes in free MPS format concern only the coding of data while the
+structure of data is the same for both fixed and free versions of the
+MPS format.
+
+In free MPS format indicator and data records\footnote{{\it Record} in
+free MPS format has the same meaning as {\it card} in fixed MPS format.}
+may have arbitrary length not limited to 80 characters. Fields of data
+records have no predefined positions, i.e. the fields may begin in any
+position, except position 1, which must be blank, and must be separated
+from each other by one or more blanks. However, the fields must appear
+in the same order as in fixed MPS format.
+
+Symbolic names in fields 2, 3, and 5 may be longer than 8
+characters\footnote{GLPK allows symbolic names having up to 255
+characters.}
+and must not contain embedded blanks.
+
+Numeric values in fields 4 and 6 are limited to 12 characters and must
+not contain embedded blanks.
+
+Only six fields on each data record are used. Any other fields are
+ignored.
+
+If the first character of any field (not necessarily fields 3 and 5)
+is the dollar sign (\$), all characters from the dollar sign to the end
+of record are considered as a comment and ignored.
+
+\section{NAME indicator card}
+
+The NAME indicator card should be the first card in the MPS file (except
+optional comment cards, which may precede the NAME card). This card
+should contain the word \verb|NAME| in the columns 1---4 and the problem
+name in the field 3. The problem name is optional and may be omitted.
+
+\section{ROWS section}
+\label{secrows}
+
+The ROWS section should start with the indicator card, which contains
+the word \verb|ROWS| in the columns 1---4.
+
+Each data card in the ROWS section specifies one row (constraint) of the
+problem. All these data cards have the following format.
+
+`\verb|N|' in the field 1 means that the row is free (unbounded):
+$$-\infty < x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
+< +\infty;$$
+
+`\verb|L|' in the field 1 means that the row is of ``less than or equal
+to'' type:
+$$-\infty < x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
+\leq b_i;$$
+
+`\verb|G|' in the field 1 means that the row is of ``greater than or
+equal to'' type:
+$$b_i \leq x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
+< +\infty;$$
+
+`\verb|E|' in the field 1 means that the row is of ``equal to'' type:
+$$x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n} \leq
+b_i,$$
+where $b_i$ is a right-hand side. Note that each constraint has a
+corresponding implictly defined auxiliary variable ($x_i$ above), whose
+value is a value of the corresponding linear form, therefore row bounds
+can be considered as bounds of such auxiliary variable.
+
+The filed 2 specifies a row name (which is considered as the name of
+the corresponding auxiliary variable).
+
+The fields 3, 4, 5, and 6 are not used and should be empty.
+
+Numerical values of all non-zero right-hand sides $b_i$ should be
+specified in the RHS section (see below). All double-bounded (ranged)
+constraints should be specified in the RANGES section (see below).
+
+\section{COLUMNS section}
+
+The COLUMNS section should start with the indicator card, which contains
+the word \verb|COLUMNS| in the columns 1---7.
+
+Each data card in the COLUMNS section specifies one or two constraint
+coefficients $a_{ij}$ and also introduces names of columns, i.e. names
+of structural variables. All these data cards have the following format.
+
+The field 1 is not used and should be empty.
+
+The field 2 specifies a column name. If this field is empty, the column
+name from the immediately preceeding data card is assumed.
+
+The field 3 specifies a row name defined in the ROWS section.
+
+The field 4 specifies a numerical value of the constraint coefficient
+$a_{ij}$, which is placed in the corresponding row and column.
+
+The fields 5 and 6 are optional. If they are used, they should contain
+a second pair ``row name---constraint coefficient'' for the same column.
+
+Elements of the constraint matrix (i.e. constraint coefficients) should
+be enumerated in the column wise manner: all elements for the current
+column should be specified before elements for the next column. However,
+the order of rows in the COLUMNS section may differ from the order of
+rows in the ROWS section.
+
+Constraint coefficients not specified in the COLUMNS section are
+considered as zeros. Therefore zero coefficients may be omitted,
+although it is allowed to explicitly specify them.
+
+\section{RHS section}
+
+The RHS section should start with the indicator card, which contains the
+word \verb|RHS| in the columns 1---3.
+
+Each data card in the RHS section specifies one or two right-hand sides
+$b_i$ (see Section \ref{secrows}, page \pageref{secrows}). All these
+data cards have the following format.
+
+The field 1 is not used and should be empty.
+
+The field 2 specifies a name of the right-hand side (RHS)
+vector\footnote{This feature allows the user to specify several RHS
+vectors in the same MPS file. However, before solving the problem a
+particular RHS vector should be chosen.}. If this field is empty, the
+RHS vector name from the immediately preceeding data card is assumed.
+
+The field 3 specifies a row name defined in the ROWS section.
+
+The field 4 specifies a right-hand side $b_i$ for the row, whose name is
+specified in the field 3. Depending on the row type $b_i$ is a lower
+bound (for the row of \verb|G| type), an upper bound (for the row of
+\verb|L| type), or a fixed value (for the row of \verb|E|
+type).\footnote{If the row is of {\tt N} type, $b_i$ is considered as
+a constant term of the corresponding linear form. Should note, however,
+this convention is non-standard.}
+
+The fields 5 and 6 are optional. If they are used, they should contain
+a second pair ``row name---right-hand side'' for the same RHS vector.
+
+All right-hand sides for the current RHS vector should be specified
+before right-hand sides for the next RHS vector. However, the order of
+rows in the RHS section may differ from the order of rows in the ROWS
+section.
+
+Right-hand sides not specified in the RHS section are considered as
+zeros. Therefore zero right-hand sides may be omitted, although it is
+allowed to explicitly specify them.
+
+\section{RANGES section}
+
+The RANGES section should start with the indicator card, which contains
+the word \verb|RANGES| in the columns 1---6.
+
+Each data card in the RANGES section specifies one or two ranges for
+double-side constraints, i.e. for constraints that are of the types
+\verb|L| and \verb|G| at the same time:
+$$l_i \leq x_i = a_{i1}x_{m+1} + a_{i2}x_{m+2} + \dots + a_{in}x_{m+n}
+\leq u_i,$$
+where $l_i$ is a lower bound, $u_i$ is an upper bound. All these data
+cards have the following format.
+
+The field 1 is not used and should be empty.
+
+The field 2 specifies a name of the range vector\footnote{This feature
+allows the user to specify several range vectors in the same MPS file.
+However, before solving the problem a particular range vector should be
+chosen.}. If this field is empty, the range vector name from the
+immediately preceeding data card is assumed.
+
+The field 3 specifies a row name defined in the ROWS section.
+
+The field 4 specifies a range value $r_i$ (see the table below) for the
+row, whose name is specified in the field 3.
+
+The fields 5 and 6 are optional. If they are used, they should contain
+a second pair ``row name---range value'' for the same range vector.
+
+All range values for the current range vector should be specified before
+range values for the next range vector. However, the order of rows in
+the RANGES section may differ from the order of rows in the ROWS
+section.
+
+For each double-side constraint specified in the RANGES section its
+lower and upper bounds are determined as follows:
+
+\begin{center}
+\begin{tabular}{cccc}
+Row type & Sign of $r_i$ & Lower bound & Upper bound \\
+\hline
+{\tt G} & $+$ or $-$ & $b_i$ & $b_i + |r_i|$ \\
+{\tt L} & $+$ or $-$ & $b_i - |r_i|$ & $b_i$ \\
+{\tt E} & $+$ & $b_i$ & $b_i + |r_i|$ \\
+{\tt E} & $-$ & $b_i - |r_i|$ & $b_i$ \\
+\end{tabular}
+\end{center}
+
+\noindent
+where $b_i$ is a right-hand side specified in the RHS section (if $b_i$
+is not specified, it is considered as zero), $r_i$ is a range value
+specified in the RANGES section.
+
+\section{BOUNDS section}
+\label{secbounds}
+
+The BOUNDS section should start with the indicator card, which contains
+the word \verb|BOUNDS| in the columns 1---6.
+
+Each data card in the BOUNDS section specifies one (lower or upper)
+bound for one structural variable (column). All these data cards have
+the following format.
+
+The indicator in the field 1 specifies the bound type:
+
+\begin{tabular}{@{}ll}
+\verb|LO| & lower bound; \\
+\verb|UP| & upper bound; \\
+\verb|FX| & fixed variable (lower and upper bounds are equal); \\
+\verb|FR| & free variable (no bounds); \\
+\verb|MI| & no lower bound (lower bound is ``minus infinity''); \\
+\verb|PL| & no upper bound (upper bound is ``plus infinity''); \\
+\end{tabular}
+
+The field 2 specifies a name of the bound vector\footnote{This feature
+allows the user to specify several bound vectors in the same MPS file.
+However, before solving the problem a particular bound vector should be
+chosen.}. If this field is empty, the bound vector name from the
+immediately preceeding data card is assumed.
+
+The field 3 specifies a column name defined in the COLUMNS section.
+
+The field 4 specifies a bound value. If the bound type in the field 1
+differs from \verb|LO|, \verb|UP|, and \verb|FX|, the value in the field
+4 is ignored and may be omitted.
+
+The fields 5 and 6 are not used and should be empty.
+
+All bound values for the current bound vector should be specified before
+bound values for the next bound vector. However, the order of columns in
+the BOUNDS section may differ from the order of columns in the COLUMNS
+section. Specification of a lower bound should precede specification of
+an upper bound for the same column (if both the lower and upper bounds
+are explicitly specified).
+
+By default, all columns (structural variables) are non-negative, i.e.
+have zero lower bound and no upper bound. Lower ($l_j$) and upper
+($u_j$) bounds of some column (structural variable $x_j$) are set in the
+following way, where $s_j$ is a corresponding bound value explicitly
+specified in the BOUNDS section:
+
+\begin{tabular}{@{}ll}
+\verb|LO| & sets $l_j$ to $s_j$; \\
+\verb|UP| & sets $u_j$ to $s_j$; \\
+\verb|FX| & sets both $l_j$ and $u_j$ to $s_j$; \\
+\verb|FR| & sets $l_j$ to $-\infty$ and $u_j$ to $+\infty$; \\
+\verb|MI| & sets $l_j$ to $-\infty$; \\
+\verb|PL| & sets $u_j$ to $+\infty$. \\
+\end{tabular}
+
+\section{ENDATA indicator card}
+
+The ENDATA indicator card should be the last card of MPS file (except
+optional comment cards, which may follow the ENDATA card). This card
+should contain the word \verb|ENDATA| in the columns 1---6.
+
+\section{Specifying objective function}
+
+It is impossible to explicitly specify the objective function and
+optimization direction in the MPS file. However, the following implicit
+rule is used by default: the first row of \verb|N| type is considered
+as a row of the objective function (i.e. the objective function is the
+corresponding auxiliary variable), which should be {\it minimized}.
+
+GLPK also allows specifying a constant term of the objective function
+as a right-hand side of the corresponding row in the RHS section.
+
+\section{Example of MPS file}
+\label{secmpsex}
+
+In order to illustrate what the MPS format is, consider the following
+example of LP problem:
+
+\medskip
+\noindent minimize
+$$
+value = .03\ bin_1 + .08\ bin_2 + .17\ bin_3 + .12\ bin_4 + .15\ bin_5
++ .21\ al + .38\ si
+$$
+
+\noindent subject to linear constraints
+$$
+\begin{array}{@{}l@{\:}l@{}}
+yield &= \ \ \ \ \;bin_1 + \ \ \ \ \;bin_2 + \ \ \ \ \;bin_3 +
+         \ \ \ \ \;bin_4 + \ \ \ \ \;bin_5 + \ \ \ \ \;al +
+         \ \ \ \ \;si \\
+FE    &= .15\ bin_1 + .04\ bin_2 + .02\ bin_3 + .04\ bin_4 + .02\ bin_5
+         + .01\ al + .03\ si \\
+CU    &= .03\ bin_1 + .05\ bin_2 + .08\ bin_3 + .02\ bin_4 + .06\ bin_5
+         + .01\ al \\
+MN    &= .02\ bin_1 + .04\ bin_2 + .01\ bin_3 + .02\ bin_4 + .02\ bin_5
+         \\
+MG    &= .02\ bin_1 + .03\ bin_2
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ + .01\ bin_5 \\
+AL    &= .70\ bin_1 + .75\ bin_2 + .80\ bin_3 + .75\ bin_4 + .80\ bin_5
+         + .97\ al \\
+SI    &= .02\ bin_1 + .06\ bin_2 + .08\ bin_3 + .12\ bin_4 + .02\ bin_5
+         + .01\ al + .97\ si \\
+\end{array}
+$$
+and bounds of (auxiliary and structural) variables
+$$
+\begin{array}{r@{\ }l@{\ }l@{\ }l@{\ }rcr@{\ }l@{\ }l@{\ }l@{\ }r}
+&&yield&=&2000&&0&\leq&bin_1&\leq&200\\
+-\infty&<&FE&\leq&60&&0&\leq&bin_2&\leq&2500\\
+-\infty&<&CU&\leq&100&&400&\leq&bin_3&\leq&800\\
+-\infty&<&MN&\leq&40&&100&\leq&bin_4&\leq&700\\
+-\infty&<&MG&\leq&30&&0&\leq&bin_5&\leq&1500\\
+1500&\leq&AL&<&+\infty&&0&\leq&al&<&+\infty\\
+250&\leq&SI&\leq&300&&0&\leq&si&<&+\infty\\
+\end{array}
+$$
+
+A complete MPS file which specifies data for this example is shown
+below (the first two comment lines show card positions).
+
+\begin{verbatim}
+*000000001111111111222222222233333333334444444444555555555566
+*234567890123456789012345678901234567890123456789012345678901
+NAME          PLAN
+ROWS
+ N  VALUE
+ E  YIELD
+ L  FE
+ L  CU
+ L  MN
+ L  MG
+ G  AL
+ L  SI
+COLUMNS
+    BIN1      VALUE           .03000   YIELD          1.00000
+              FE              .15000   CU              .03000
+              MN              .02000   MG              .02000
+              AL              .70000   SI              .02000
+    BIN2      VALUE           .08000   YIELD          1.00000
+              FE              .04000   CU              .05000
+              MN              .04000   MG              .03000
+              AL              .75000   SI              .06000
+    BIN3      VALUE           .17000   YIELD          1.00000
+              FE              .02000   CU              .08000
+              MN              .01000   AL              .80000
+              SI              .08000
+    BIN4      VALUE           .12000   YIELD          1.00000
+              FE              .04000   CU              .02000
+              MN              .02000   AL              .75000
+              SI              .12000
+    BIN5      VALUE           .15000   YIELD          1.00000
+              FE              .02000   CU              .06000
+              MN              .02000   MG              .01000
+              AL              .80000   SI              .02000
+    ALUM      VALUE           .21000   YIELD          1.00000
+              FE              .01000   CU              .01000
+              AL              .97000   SI              .01000
+    SILICON   VALUE           .38000   YIELD          1.00000
+              FE              .03000   SI              .97000
+RHS
+    RHS1      YIELD       2000.00000   FE            60.00000
+              CU           100.00000   MN            40.00000
+              SI           300.00000
+              MG            30.00000   AL          1500.00000
+RANGES
+    RNG1      SI            50.00000
+BOUNDS
+ UP BND1      BIN1         200.00000
+ UP           BIN2        2500.00000
+ LO           BIN3         400.00000
+ UP           BIN3         800.00000
+ LO           BIN4         100.00000
+ UP           BIN4         700.00000
+ UP           BIN5        1500.00000
+ENDATA
+\end{verbatim}
+
+\section{MIP features}
+
+The MPS format provides two ways for introducing integer variables into
+the problem.
+
+The first way is most general and based on using special marker cards
+INTORG and INTEND. These marker cards are placed in the COLUMNS section.
+The INTORG card indicates the start of a group of integer variables
+(columns), and the card INTEND indicates the end of the group. The MPS
+file may contain arbitrary number of the marker cards.
+
+The marker cards have the same format as the data cards (see Section
+\ref{secmps}, page \pageref{secmps}).
+
+The fields 1, 2, and 6 are not used and should be empty.
+
+The field 2 should contain a marker name. This name may be arbitrary.
+
+The field 3 should contain the word \verb|'MARKER'| (including
+apostrophes).
+
+The field 5 should contain either the word \verb|'INTORG'| (including
+apostrophes) for the marker card, which begins a group of integer
+columns, or the word \verb|'INTEND'| (including apostrophes) for the
+marker card, which ends the group.
+
+The second way is less general but more convenient in some cases. It
+allows the user declaring integer columns using three additional types
+of bounds, which are specified in the field 1 of data cards in the
+BOUNDS section (see Section \ref{secbounds}, page \pageref{secbounds}):
+
+\begin{tabular}{@{}lp{112.3mm}@{}}
+\verb|LI| & lower integer. This bound type specifies that the
+corresponding column (structural variable), whose name is specified in
+field 3, is of integer kind. In this case an lower bound of the
+column should be specified in field 4 (like in the case of \verb|LO|
+bound type). \\
+\verb|UI| & upper integer. This bound type specifies that the
+corresponding column (structural variable), whose name is specified in
+field 3, is of integer kind. In this case an upper bound of the
+column should be specified in field 4 (like in the case of \verb|UP|
+bound type). \\
+\end{tabular}
+
+\pagebreak
+
+\begin{tabular}{@{}lp{112.3mm}@{}}
+\verb|BV| & binary variable. This bound type specifies that the
+corresponding column (structural variable), whose name is specified in
+the field 3, is of integer kind, its lower bound is zero, and its upper
+bound is one (thus, such variable being of integer kind can have only
+two values zero and one). In this case a numeric value specified in the
+field 4 is ignored and may be omitted.\\
+\end{tabular}
+
+Consider the following example of MIP problem:
+
+\medskip
+
+\noindent
+\hspace{1in} minimize
+$$Z = 3 x_1 + 7 x_2 - x_3 + x4$$
+\hspace{1in} subject to linear constraints
+$$
+\begin{array}{c}
+\nonumber r_1 = 2   x_1 - \ \ x_2 + \ \ x_3 - \ \;x_4 \\
+\nonumber r_2 = \ \;x_1 - \ \;x_2 - 6   x_3 + 4   x_4 \\
+\nonumber r_3 = 5   x_1 +   3 x_2 \ \ \ \ \ \ \ \ \ + \ \ x_4 \\
+\end{array}
+$$
+\hspace{1in} and bound of variables
+$$
+\begin{array}{cccl}
+\nonumber 1 \leq r_1 < +\infty && 0 \leq x_1 \leq 4 &{\rm(continuous)}\\
+\nonumber 8 \leq r_2 < +\infty && 2 \leq x_2 \leq 5 &{\rm(integer)}   \\
+\nonumber 5 \leq r_3 < +\infty && 0 \leq x_3 \leq 1 &{\rm(integer)}   \\
+\nonumber                      && 3 \leq x_4 \leq 8 &{\rm(continuous)}\\
+\end{array}
+$$
+
+The corresponding MPS file may look like the following:
+
+\begin{verbatim}
+NAME          SAMP1
+ROWS
+ N  Z
+ G  R1
+ G  R2
+ G  R3
+COLUMNS
+    X1        R1                2.0    R2                 1.0
+    X1        R3                5.0    Z                  3.0
+    MARK0001  'MARKER'                 'INTORG'
+    X2        R1               -1.0    R2                -1.0
+    X2        R3                3.0    Z                  7.0
+    X3        R1                1.0    R2                -6.0
+    X3        Z                -1.0
+    MARK0002  'MARKER'                 'INTEND'
+    X4        R1               -1.0    R2                 4.0
+    X4        R3                1.0    Z                  1.0
+RHS
+    RHS1      R1                1.0
+    RHS1      R2                8.0
+    RHS1      R3                5.0
+BOUNDS
+ UP BND1      X1                4.0
+ LO BND1      X2                2.0
+ UP BND1      X2                5.0
+ UP BND1      X3                1.0
+ LO BND1      X4                3.0
+ UP BND1      X4                8.0
+ENDATA
+\end{verbatim}
+
+The same example may be coded without INTORG/INTEND markers using the
+bound type UI for the variable $x_2$ and the bound type BV for the
+variable $x_3$:
+
+\begin{verbatim}
+NAME          SAMP2
+ROWS
+ N  Z
+ G  R1
+ G  R2
+ G  R3
+COLUMNS
+    X1        R1                2.0    R2                 1.0
+    X1        R3                5.0    Z                  3.0
+    X2        R1               -1.0    R2                -1.0
+    X2        R3                3.0    Z                  7.0
+    X3        R1                1.0    R2                -6.0
+    X3        Z                -1.0
+    X4        R1               -1.0    R2                 4.0
+    X4        R3                1.0    Z                  1.0
+RHS
+    RHS1      R1                1.0
+    RHS1      R2                8.0
+    RHS1      R3                5.0
+BOUNDS
+ UP BND1      X1                4.0
+ LO BND1      X2                2.0
+ UI BND1      X2                5.0
+ BV BND1      X3
+ LO BND1      X4                3.0
+ UP BND1      X4                8.0
+ENDATA
+\end{verbatim}
+
+%\section{Specifying predefined basis}
+%\label{secbas}
+%
+%The MPS format can also be used to specify some predefined basis for an
+%LP problem, i.e. to specify which rows and columns are basic and which
+%are non-basic.
+%
+%The order of a basis file in the MPS format is:
+%
+%$\bullet$ NAME indicator card;
+%
+%$\bullet$ data cards (can appear in arbitrary order);
+%
+%$\bullet$ ENDATA indicator card.
+%
+%Each data card specifies either a pair "basic column---non-basic row"
+%or a non-basic column. All the data cards have the following format.
+%
+%`\verb|XL|' in the field 1 means that a column, whose name is given in
+%the field 2, is basic, and a row, whose name is given in the field 3,
+%is non-basic and placed on its lower bound.
+%
+%`\verb|XU|' in the field 1 means that a column, whose name is given in
+%the field 2, is basic, and a row, whose name is given in the field 3,
+%is non-basic and placed on its upper bound.
+%
+%`\verb|LL|' in the field 1 means that a column, whose name is given in
+%the field 3, is non-basic and placed on its lower bound.
+%
+%`\verb|UL|' in the field 1 means that a column, whose name is given in
+%the field 3, is non-basic and placed on its upper bound.
+%
+%The field 2 contains a column name.
+%
+%If the indicator given in the field 1 is `\verb|XL|' or `\verb|XU|',
+%the field 3 contains a row name. Otherwise, if the indicator is
+%`\verb|LL|' or `\verb|UL|', the field 3 is not used and should be
+%empty.
+%
+%The field 4, 5, and 6 are not used and should be empty.
+%
+%A basis file in the MPS format acts like a patch: it doesn't specify
+%a basis completely, instead that it is just shows in what a given basis
+%differs from the "standard" basis, where all rows (auxiliary variables)
+%are assumed to be basic and all columns (structural variables) are
+%assumed to be non-basic.
+%
+%As an example here is a basis file that specifies an optimal basis
+%for the example LP problem given in Section \ref{secmpsex},
+%Page \pageref{secmpsex}:
+%
+%\pagebreak
+%
+%\begin{verbatim}
+%*000000001111111111222222222233333333334444444444555555555566
+%*234567890123456789012345678901234567890123456789012345678901
+%NAME          PLAN
+% XL BIN2      YIELD
+% XL BIN3      FE
+% XL BIN4      MN
+% XL ALUM      AL
+% XL SILICON   SI
+% LL BIN1
+% LL BIN5
+%ENDATA
+%\end{verbatim}
+
+%* eof *%
Index: deps/glpk/doc/glpk09.tex
===================================================================
--- deps/glpk/doc/glpk09.tex	(revision 9)
+++ deps/glpk/doc/glpk09.tex	(revision 9)
@@ -0,0 +1,413 @@
+%* glpk09.tex *%
+
+\chapter{CPLEX LP Format}
+\label{chacplex}
+
+\section{Prelude}
+
+The CPLEX LP format\footnote{The CPLEX LP format was developed in
+the end of 1980's by CPLEX Optimization, Inc. as an input format for
+the CPLEX linear programming system. Although the CPLEX LP format is
+not as widely used as the MPS format, being row-oriented it is more
+convenient for coding mathematical programming models by human. This
+appendix describes only the features of the CPLEX LP format which are
+implemented in the GLPK package.} is intended for coding LP/MIP problem
+data. It is a row-oriented format that assumes the formulation of LP/MIP
+problem (1.1)---(1.3) (see Section \ref{seclp}, page \pageref{seclp}).
+
+CPLEX LP file is a plain text file written in CPLEX LP format. Each text
+line of this file may contain up to 255 characters\footnote{GLPK allows
+text lines of arbitrary length.}. Blank lines are ignored. If a line
+contains the backslash character ($\backslash$), this character and
+everything that follows it until the end of line are considered as a
+comment and also ignored.
+
+An LP file is coded by the user using the following elements:
+
+$\bullet$ keywords;
+
+$\bullet$ symbolic names;
+
+$\bullet$ numeric constants;
+
+$\bullet$ delimiters;
+
+$\bullet$ blanks.
+
+\newpage
+
+{\it Keywords} which may be used in the LP file are the following:
+
+\begin{verbatim}
+      minimize        minimum        min
+      maximize        maximum        max
+      subject to      such that      s.t.      st.      st
+      bounds          bound
+      general         generals       gen
+      integer         integers       int
+      binary          binaries       bin
+      infinity        inf
+      free
+      end
+\end{verbatim}
+
+\noindent
+All the keywords are case insensitive. Keywords given above on the same
+line are equivalent. Any keyword (except \verb|infinity|, \verb|inf|,
+and \verb|free|) being used in the LP file must start at the beginning
+of a text line.
+
+{\it Symbolic names} are used to identify the objective function,
+constraints (rows), and variables (columns). All symbolic names are case
+sensitive and may contain up to 16 alphanumeric characters\footnote{GLPK
+allows symbolic names having up to 255 characters.} (\verb|a|, \dots,
+\verb|z|, \verb|A|, \dots, \verb|Z|, \verb|0|, \dots, \verb|9|) as well
+as the following characters:
+
+\begin{verbatim}
+!  "  #  $  %  &  (  )  /  ,  .  ;  ?  @  _  `  '  {  }  |  ~
+\end{verbatim}
+
+\noindent
+with exception that no symbolic name can begin with a digit or a period.
+
+{\it Numeric constants} are used to denote constraint and objective
+coefficients, right-hand sides of constraints, and bounds of variables.
+They are coded in the standard form $xx$\verb|E|$syy$, where $xx$ is
+a real number with optional decimal point, $s$ is a sign (\verb|+| or
+\verb|-|), $yy$ is an integer decimal exponent. Numeric constants may
+contain arbitrary number of characters. The exponent part is optional.
+The letter `\verb|E|' can be coded as `\verb|e|'. If the sign $s$ is
+omitted, plus is assumed.
+
+{\it Delimiters} that may be used in the LP file are the following:
+
+\begin{verbatim}
+      :
+      +
+      -
+      <   <=   =<
+      >   >=   =>
+      =
+\end{verbatim}
+
+\noindent
+Delimiters given above on the same line are equivalent. The meaning of
+the delimiters will be explained below.
+
+{\it Blanks} are non-significant characters. They may be used freely to
+improve readability of the LP file. Besides, blanks should be used to
+separate elements from each other if there is no other way to do that
+(for example, to separate a keyword from a following symbolic name).
+
+The order of an LP file is:
+
+$\bullet$ objective function definition;
+
+$\bullet$ constraints section;
+
+$\bullet$ bounds section;
+
+$\bullet$ general, integer, and binary sections (can appear in arbitrary
+order);
+
+$\bullet$ end keyword.
+
+These components are discussed in following sections.
+
+\section{Objective function definition}
+
+The objective function definition must appear first in the LP file. It
+defines the objective function and specifies the optimization direction.
+
+The objective function definition has the following form:
+$$
+\left\{
+\begin{array}{@{}c@{}}
+{\tt minimize} \\ {\tt maximize}
+\end{array}
+\right\}\ f\ {\tt :}\ s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x
+$$
+where $f$ is a symbolic name of the objective function, $s$ is a sign
+\verb|+| or \verb|-|, $c$ is a numeric constant that denotes an
+objective coefficient, $x$ is a symbolic name of a variable.
+
+If necessary, the objective function definition can be continued on as
+many text lines as desired.
+
+The name of the objective function is optional and may be omitted
+(together with the semicolon that follows it). In this case the default
+name `\verb|obj|' is assigned to the objective function.
+
+If the very first sign $s$ is omitted, the sign plus is assumed. Other
+signs cannot be omitted.
+
+If some objective coefficient $c$ is omitted, 1 is assumed.
+
+Symbolic names $x$ used to denote variables are recognized by context
+and therefore needn't to be declared somewhere else.
+
+Here is an example of the objective function definition:
+
+\begin{verbatim}
+   Minimize Z : - x1 + 2 x2 - 3.5 x3 + 4.997e3x(4) + x5 + x6 +
+      x7 - .01x8
+\end{verbatim}
+
+\section{Constraints section}
+
+The constraints section must follow the objective function definition.
+It defines a system of equality and/or inequality constraints.
+
+The constraint section has the following form:
+
+\begin{center}
+\begin{tabular}{l}
+\verb|subject to| \\
+{\it constraint}$_1$ \\
+{\it constraint}$_2$ \\
+\hspace{20pt}\dots \\
+{\it constraint}$_m$ \\
+\end{tabular}
+\end{center}
+
+\noindent where {\it constraint}$_i, i=1,\dots,m,$ is a particular
+constraint definition.
+
+Each constraint definition can be continued on as many text lines as
+desired. However, each constraint definition must begin on a new line
+except the very first constraint definition which can begin on the same
+line as the keyword `\verb|subject to|'.
+
+Constraint definitions have the following form:
+$$
+r\ {\tt:}\ s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x
+\ \left\{
+\begin{array}{@{}c@{}}
+\mbox{\tt<=} \\ \mbox{\tt>=} \\ \mbox{\tt=}
+\end{array}
+\right\}\ b
+$$
+where $r$ is a symbolic name of a constraint, $s$ is a sign \verb|+| or
+\verb|-|, $c$ is a numeric constant that denotes a constraint
+coefficient, $x$ is a symbolic name of a variable, $b$ is a right-hand
+side.
+
+The name $r$ of a constraint (which is the name of the corresponding
+auxiliary variable) is optional and may be omitted (together with the
+semicolon that follows it). In this case the default names like
+`\verb|r.nnn|' are assigned to unnamed constraints.
+
+The linear form $s\ c\ x\ s\ c\ x\ \dots\ s\ c\ x$ in the left-hand
+side of a constraint definition has exactly the same meaning as in the
+case of the objective function definition (see above).
+
+After the linear form one of the following delimiters that indicate
+the constraint sense must be specified:
+
+\verb|<=| \ means `less than or equal to'
+
+\verb|>=| \ means `greater than or equal to'
+
+\verb|= | \ means `equal to'
+
+The right hand side $b$ is a numeric constant with an optional sign.
+
+Here is an example of the constraints section:
+
+\begin{verbatim}
+   Subject To
+      one: y1 + 3 a1 - a2 - b >= 1.5
+      y2 + 2 a3 + 2
+         a4 - b >= -1.5
+      two : y4 + 3 a1 + 4 a5 - b <= +1
+      .20y5 + 5 a2 - b = 0
+      1.7 y6 - a6 + 5 a777 - b >= 1
+\end{verbatim}
+
+(Should note that it is impossible to express ranged constraints in the
+CPLEX LP format. Each a ranged constraint can be coded as two
+constraints with identical linear forms in the left-hand side, one of
+which specifies a lower bound and other does an upper one of the
+original ranged constraint.)
+
+\section{Bounds section}
+
+The bounds section is intended to define bounds of variables. This
+section is optional; if it is specified, it must follow the constraints
+section. If the bound section is omitted, all variables are assumed to
+be non-negative (i.e. that they have zero lower bound and no upper
+bound).
+
+The bounds section has the following form:
+
+\begin{center}
+\begin{tabular}{l}
+\verb|bounds| \\
+{\it definition}$_1$ \\
+{\it definition}$_2$ \\
+\hspace{20pt}\dots \\
+{\it definition}$_p$ \\
+\end{tabular}
+\end{center}
+
+\noindent
+where {\it definition}$_k, k=1,\dots,p,$ is a particular bound
+definition.
+
+Each bound definition must begin on a new line\footnote{The GLPK
+implementation allows several bound definitions to be placed on the same
+line.} except the very first bound definition which can begin on the
+same line as the keyword `\verb|bounds|'.
+
+Syntactically constraint definitions can have one of the following six
+forms:
+
+\begin{center}
+\begin{tabular}{ll}
+$x$ \verb|>=| $l$ &              specifies a lower bound \\
+$l$ \verb|<=| $x$ &              specifies a lower bound \\
+$x$ \verb|<=| $u$ &              specifies an upper bound \\
+$l$ \verb|<=| $x$ \verb|<=| $u$ &specifies both lower and upper bounds\\
+$x$ \verb|=| $t$                &specifies a fixed value \\
+$x$ \verb|free|                 &specifies free variable
+\end{tabular}
+\end{center}
+
+\noindent
+where $x$ is a symbolic name of a variable, $l$ is a numeric constant
+with an optional sign that defines a lower bound of the variable or
+\verb|-inf| that means that the variable has no lower bound, $u$ is a
+numeric constant with an optional sign that defines an upper bound of
+the variable or \verb|+inf| that means that the variable has no upper
+bound, $t$ is a numeric constant with an optional sign that defines a
+fixed value of the variable.
+
+By default all variables are non-negative, i.e. have zero lower bound
+and no upper bound. Therefore definitions of these default bounds can be
+omitted in the bounds section.
+
+Here is an example of the bounds section:
+
+\begin{verbatim}
+   Bounds
+      -inf <= a1 <= 100
+      -100 <= a2
+      b <= 100
+      x2 = +123.456
+      x3 free
+\end{verbatim}
+
+\section{General, integer, and binary sections}
+
+The general, integer, and binary sections are intended to define
+some variables as integer or binary. All these sections are optional
+and needed only in case of MIP problems. If they are specified, they
+must follow the bounds section or, if the latter is omitted, the
+constraints section.
+
+All the general, integer, and binary sections have the same form as
+follows:
+
+\begin{center}
+\begin{tabular}{l}
+$
+\left\{
+\begin{array}{@{}l@{}}
+\verb|general| \\
+\verb|integer| \\
+\verb|binary | \\
+\end{array}
+\right\}
+$ \\
+\hspace{10pt}$x_1$ \\
+\hspace{10pt}$x_2$ \\
+\hspace{10pt}\dots \\
+\hspace{10pt}$x_q$ \\
+\end{tabular}
+\end{center}
+
+\noindent
+where $x_k$ is a symbolic name of variable, $k=1,\dots,q$.
+
+Each symbolic name must begin on a new line\footnote{The GLPK
+implementation allows several symbolic names to be placed on the same
+line.} except the very first symbolic name which can begin on the same
+line as the keyword `\verb|general|', `\verb|integer|', or
+`\verb|binary|'.
+
+If a variable appears in the general or the integer section, it is
+assumed to be general integer variable. If a variable appears in the
+binary section, it is assumed to be binary variable, i.e. an integer
+variable whose lower bound is zero and upper bound is one. (Note that
+if bounds of a variable are specified in the bounds section and then
+the variable appears in the binary section, its previously specified
+bounds are ignored.)
+
+Here is an example of the integer section:
+
+\begin{verbatim}
+   Integer
+      z12
+      z22
+      z35
+\end{verbatim}
+
+\section{End keyword}
+
+The keyword `\verb|end|' is intended to end the LP file. It must begin
+on a separate line and no other elements (except comments and blank
+lines) must follow it. Although this keyword is optional, it is strongly
+recommended to include it in the LP file.
+
+\section{Example of CPLEX LP file}
+
+Here is a complete example of CPLEX LP file that corresponds to the
+example given in Section \ref{secmpsex}, page \pageref{secmpsex}.
+
+{\footnotesize
+\begin{verbatim}
+\* plan.lp *\
+
+Minimize
+   value: .03 bin1 + .08 bin2 + .17 bin3 + .12 bin4 + .15 bin5 +
+          .21 alum + .38 silicon
+
+Subject To
+   yield:     bin1 +     bin2 +     bin3 +     bin4 +     bin5 +
+              alum +     silicon                                 =  2000
+
+   fe:    .15 bin1 + .04 bin2 + .02 bin3 + .04 bin4 + .02 bin5 +
+          .01 alum + .03 silicon                                 <=   60
+
+   cu:    .03 bin1 + .05 bin2 + .08 bin3 + .02 bin4 + .06 bin5 +
+          .01 alum                                               <=  100
+
+   mn:    .02 bin1 + .04 bin2 + .01 bin3 + .02 bin4 + .02 bin5   <=   40
+
+   mg:    .02 bin1 + .03 bin2                       + .01 bin5   <=   30
+
+   al:    .70 bin1 + .75 bin2 + .80 bin3 + .75 bin4 + .80 bin5 +
+          .97 alum                                               >= 1500
+
+   si1:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
+          .01 alum + .97 silicon                                 >=  250
+
+   si2:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
+          .01 alum + .97 silicon                                 <=  300
+
+Bounds
+          bin1 <=  200
+          bin2 <= 2500
+   400 <= bin3 <=  800
+   100 <= bin4 <=  700
+          bin5 <= 1500
+
+End
+
+\* eof *\
+\end{verbatim}
+
+}
+
+%* eof *%
Index: deps/glpk/doc/glpk10.tex
===================================================================
--- deps/glpk/doc/glpk10.tex	(revision 9)
+++ deps/glpk/doc/glpk10.tex	(revision 9)
@@ -0,0 +1,210 @@
+%* glpk10.tex *%
+
+\chapter{Stand-alone LP/MIP Solver}
+\label{chaglpsol}
+
+The GLPK package includes the program \verb|glpsol|, which is a
+stand-alone LP/MIP solver. This program can be invoked from the command
+line of from the shell to read LP/MIP problem data in any format
+supported by GLPK, solve the problem, and write the problem solution
+obtained to an output text file.
+
+\subsubsection*{Usage}
+
+\noindent
+\verb|glpsol| [{\it options\dots}] [{\it filename}]
+
+\subsubsection*{General options}
+
+\noindent
+\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
+\verb|--mps|      &  read LP/MIP problem in fixed MPS format \\
+\verb|--freemps|  &  read LP/MIP problem in free MPS format (default)\\
+\verb|--lp|       &  read LP/MIP problem in CPLEX LP format \\
+\verb|--glp|      &  read LP/MIP problem in GLPK format \\
+\verb|--math|     &  read LP/MIP model written in GNU MathProg modeling
+                     language \\
+\multicolumn{2}{@{}l}{{\tt -m} {\it filename}, {\tt --model}
+{\it filename}} \\
+                  &  read model section and optional data section from
+                     {\it filename} (the same as \verb|--math|) \\
+\multicolumn{2}{@{}l}{{\tt -d} {\it filename}, {\tt --data}
+{\it filename}} \\
+                  &  read data section from {\it filename}
+                     (for \verb|--math| only); if model file also has
+                     data section, that section is ignored \\
+\multicolumn{2}{@{}l}{{\tt -y} {\it filename}, {\tt --display}
+{\it filename}} \\
+                  &  send display output to {\it filename}
+                     (for \verb|--math| only); by default the output is
+                     sent to \verb|stdout| \\
+\end{tabular}
+
+\noindent
+\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
+\verb|--seed| {\it value}
+                  &  initialize pseudo-random number generator used in
+                     MathProg model with specified seed (any integer);
+                     if the seed value is specified as \verb|?|
+                     (question mark), some random seed will be used\\
+\verb|--mincost|  &  read min-cost flow problem in DIMACS format\\
+\verb|--maxflow|  &  read maximum flow problem in DIMACS format\\
+\verb|--simplex|  &  use simplex method (default) \\
+\verb|--interior| &  use interior point method (for pure LP only) \\
+\multicolumn{2}{@{}l}{{\tt -r} {\it filename}, {\tt --read}
+{\it filename}} \\
+                  &  read solution from {\it filename} rather to find
+                     it with the solver \\
+\verb|--min|      &  minimization \\
+\verb|--max|      &  maximization \\
+\verb|--scale|    &  scale problem (default) \\
+\verb|--noscale|  &  do not scale problem \\
+\multicolumn{2}{@{}l}{{\tt -o} {\it filename}, {\tt --output}
+{\it filename}} \\
+                  &  write solution to {\it filename} in printable
+                     format \\
+\multicolumn{2}{@{}l}{{\tt -w} {\it filename}, {\tt --write}
+{\it filename}} \\
+                  &  write solution to {\it filename} in plain text
+                     format \\
+\multicolumn{2}{@{}l}{{\tt --ranges} {\it filename}} \\
+                  &  write sensitivity analysis report to {\it filename}
+                     in printable format (simplex only) \\
+\verb|--tmlim| {\it nnn}
+                  &  limit solution time to {\it nnn} seconds
+                     (\verb|--tmlim 0| allows obtaining solution at
+                     initial point) \\
+\verb|--memlim| {\it nnn}
+                  &  limit available memory to {\it nnn} megabytes \\
+\verb|--check|    &  do not solve problem, check input data only \\
+\verb|--name| {\it probname}
+                  &  change problem name to {\it probname} \\
+\verb|--wmps| {\it filename}
+                  &  write problem to {\it filename} in fixed MPS
+                     format \\
+\multicolumn{2}{@{}l}{{\tt --wfreemps} {\it filename}} \\
+                  &  write problem to {\it filename} in free MPS
+                     format \\
+\verb|--wlp| {\it filename}
+                  &  write problem to {\it filename} in CPLEX LP
+                     format \\
+\verb|--wglp| {\it filename}
+                  &  write problem to {\it filename} in GLPK format \\
+\verb|--log| {\it filename}
+                  &  write copy of terminal output to {\it filename} \\
+\verb|-h|, \verb|--help|
+                  &  display this help information and exit \\
+\verb|-v|, \verb|--version|
+                  &  display program version and exit \\
+\end{tabular}
+
+\subsection*{LP basis factorization options}
+
+\noindent
+\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
+\verb|--luf|      &  LU + Forrest--Tomlin update \\
+                  &  (faster, less stable; default) \\
+\verb|--cbg|      &  LU + Schur complement + Bartels--Golub update \\
+                  &  (slower, more stable) \\
+\verb|--cgr|      &  LU + Schur complement + Givens rotation update \\
+                  &  (slower, more stable) \\
+\end{tabular}
+
+\subsubsection*{Options specific to the simplex solver}
+
+\noindent
+\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
+\verb|--primal|   &  use primal simplex (default) \\
+\verb|--dual|     &  use dual simplex \\
+\verb|--std|      &  use standard initial basis of all slacks \\
+\verb|--adv|      &  use advanced initial basis (default) \\
+\verb|--bib|      &  use Bixby's initial basis\\
+\verb|--ini| {\it filename}
+                  &  use as initial basis previously saved with
+                     \verb|-w| \\
+                  & (disables LP presolver) \\
+\verb|--steep|    &  use steepest edge technique (default) \\
+\verb|--nosteep|  &  use standard ``textbook'' pricing \\
+\verb|--relax|    &  use Harris' two-pass ratio test (default) \\
+\verb|--norelax|  &  use standard ``textbook'' ratio test \\
+\verb|--presol|   &  use LP presolver (default; assumes \verb|--scale|
+                     and \verb|--adv|) \\
+\verb|--nopresol| &  do not use LP presolver \\
+\verb|--exact|    & use simplex method based on exact arithmetic \\
+\verb|--xcheck|   & check final basis using exact arithmetic \\
+\end{tabular}
+
+\subsubsection*{Options specific to the interior-point solver}
+
+\noindent
+\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
+\verb|--nord|     &  use natural (original) ordering \\
+\verb|--qmd|      &  use quotient minimum degree ordering \\
+\verb|--amd|      &  use approximate minimum degree ordering (default)\\
+\verb|--symamd|   &  use approximate minimum degree ordering \\
+\end{tabular}
+
+\subsubsection*{Options specific to the MIP solver}
+
+\noindent
+\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
+\verb|--nomip|    &  consider all integer variables as continuous
+                     (allows solving MIP as pure LP) \\
+\verb|--first|    &  branch on first integer variable \\
+\verb|--last|     &  branch on last integer variable \\
+\verb|--mostf|    &  branch on most fractional variable \\
+\end{tabular}
+
+\noindent
+\begin{tabular}{@{}p{30mm}p{92.3mm}@{}}
+\verb|--drtom|    &  branch using heuristic by Driebeck and Tomlin
+                     (default) \\
+\verb|--pcost|    &  branch using hybrid pseudocost heuristic (may be
+                     useful for hard instances) \\
+\verb|--dfs|      &  backtrack using depth first search \\
+\verb|--bfs|      &  backtrack using breadth first search \\
+\verb|--bestp|    &  backtrack using the best projection heuristic
+                     (default) \\
+\verb|--bestb|    &  backtrack using node with best local bound \\
+\verb|--intopt|   &  use MIP presolver (default)\\
+\verb|--nointopt| &  do not use MIP presolver\\
+\verb|--binarize| &  replace general integer variables by binary ones
+                     (assumes \verb|--intopt|)\\
+\verb|--fpump|    & apply feasibility pump heuristic\\
+\verb|--gomory|   &  generate Gomory's mixed integer cuts\\
+\verb|--mir|      &  generate MIR (mixed integer rounding) cuts\\
+\verb|--cover|    &  generate mixed cover cuts\\
+\verb|--clique|   &  generate clique cuts\\
+\verb|--cuts|     &  generate cuts of all classes above (assumes
+                     \verb|--intopt|)\\
+\verb|--mipgap| {\it tol}
+                  & set relative mip gap tolerance to {\it tol}\\
+\end{tabular}
+
+\bigskip
+
+\noindent
+For description of the MPS format see Appendix \ref{champs},
+page \pageref{champs}.
+
+\bigskip
+
+\noindent
+For description of the CPLEX LP format see Appendix \ref{chacplex},
+page \pageref{chacplex}.
+
+\bigskip
+
+\noindent
+For description of the modeling language see the document ``Modeling
+Language GNU MathProg: Language Reference'' included in the GLPK
+distribution.
+
+\bigskip
+
+\noindent
+For description of the DIMACS min-cost flow problem format and DIMACS
+maximum flow problem format see the document ``GLPK: Graph and Network
+Routines'' included in the GLPK distribution.
+
+%* eof *%
Index: deps/glpk/doc/glpk11.tex
===================================================================
--- deps/glpk/doc/glpk11.tex	(revision 9)
+++ deps/glpk/doc/glpk11.tex	(revision 9)
@@ -0,0 +1,124 @@
+%* glpk11.tex *%
+
+\begin{footnotesize}
+
+\chapter{External Software Modules Used In GLPK}
+
+In the GLPK package there are used some external software modules
+listed in this Appendix. Note that these modules are {\it not} part of
+GLPK, but are used with GLPK and included in the distribution.
+
+\section{AMD}
+
+AMD Version 2.2, Copyright {\copyright} 2007 by Timothy A. Davis,
+Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+\subsection*{Description}
+
+AMD is a set of routines for pre-ordering sparse matrices prior to
+Cholesky or LU factorization, using the approximate minimum degree
+ordering algorithm.
+
+\subsection*{License}
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License
+as published by the Free Software Foundation; either version 2.1 of
+the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA.
+
+Permission is hereby granted to use or copy this program under the
+terms of the GNU LGPL, provided that the Copyright, this License,
+and the Availability of the original version is retained on all
+copies.  User documentation of any code that uses this code or any
+modified version of this code must cite the Copyright, this License,
+the Availability note, and ``Used by permission.''  Permission to
+modify the code and to distribute modified code is granted, provided
+the Copyright, this License, and the Availability note are retained,
+and a notice that the code was modified is included.
+
+AMD is available under alternate licences; contact T. Davis for
+details.
+
+\subsection*{Availability}
+
+\verb|http://www.cise.ufl.edu/research/sparse/amd|
+
+\bigskip
+
+\noindent
+Used by permission.
+
+\section{COLAMD/SYMAMD}
+
+COLAMD/SYMAMD Version 2.7, Copyright {\copyright} 1998-2007, Timothy A.
+Davis, All Rights Reserved.
+
+\subsection*{Description}
+
+\paragraph{colamd:} an approximate minimum degree column ordering
+algorithm, for LU factorization of symmetric or unsymmetric matrices,
+QR factorization, least squares, interior point methods for linear
+programming problems, and other related problems.
+
+\paragraph{symamd:} an approximate minimum degree ordering algorithm
+for Cholesky factorization of symmetric matrices.
+
+\subsection*{Authors}
+
+The authors of the code itself are Stefan I. Larimore and Timothy A.
+Davis (davis at cise.ufl.edu), University of Florida.  The algorithm
+was developed in collaboration with John Gilbert, Xerox PARC, and
+Esmond Ng, Oak Ridge National Laboratory.
+
+\subsection*{License}
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License
+as published by the Free Software Foundation; either version 2.1 of
+the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA.
+
+Permission is hereby granted to use or copy this program under the
+terms of the GNU LGPL, provided that the Copyright, this License,
+and the Availability of the original version is retained on all
+copies.  User documentation of any code that uses this code or any
+modified version of this code must cite the Copyright, this License,
+the Availability note, and ``Used by permission.''  Permission to
+modify the code and to distribute modified code is granted, provided
+the Copyright, this License, and the Availability note are retained,
+and a notice that the code was modified is included.
+
+COLAMD is also available under alternate licenses, contact T. Davis for
+details.
+
+\subsection*{Availability}
+
+\verb|http://www.cise.ufl.edu/research/sparse/colamd|
+
+\bigskip
+
+\noindent
+Used by permission.
+
+\end{footnotesize}
+
+%* eof *%
Index: deps/glpk/doc/glpk12.tex
===================================================================
--- deps/glpk/doc/glpk12.tex	(revision 9)
+++ deps/glpk/doc/glpk12.tex	(revision 9)
@@ -0,0 +1,726 @@
+%* glpk12.tex *%
+
+\begin{footnotesize}
+
+\chapter*{\sf\bfseries GNU General Public License}
+\addcontentsline{toc}{chapter}{GNU General Public License}
+
+\begin{center}
+{\bf Version 3, 29 June 2007}
+\end{center}
+
+\begin{quotation}
+\noindent
+Copyright {\copyright} 2007 Free Software Foundation, Inc.
+\verb|<http://fsf.org/>|
+\end{quotation}
+
+\begin{quotation}
+\noindent
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+\end{quotation}
+
+\section*{Preamble}
+
+\noindent\indent
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+\section*{TERMS AND CONDITIONS}
+
+\subsubsection*{0. Definitions.}
+
+\noindent\indent
+  ``This License'' refers to version 3 of the GNU General Public
+License.
+
+  ``Copyright'' also means copyright-like laws that apply to other kinds
+of works, such as semiconductor masks.
+
+  ``The Program'' refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as ``you''.  ``Licensees'' and
+``recipients'' may be individuals or organizations.
+
+  To ``modify'' a work means to copy from or adapt all or part of the
+work in a fashion requiring copyright permission, other than the making
+of an exact copy.  The resulting work is called a ``modified version''
+of the earlier work or a work ``based on'' the earlier work.
+
+  A ``covered work'' means either the unmodified Program or a work based
+on the Program.
+
+  To ``propagate'' a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To ``convey'' a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays ``Appropriate Legal Notices''
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+\subsubsection*{1. Source Code.}
+
+\noindent\indent
+  The ``source code'' for a work means the preferred form of the work
+for making modifications to it.  ``Object code'' means any non-source
+form of a work.
+
+  A ``Standard Interface'' means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The ``System Libraries'' of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+``Major Component'', in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The ``Corresponding Source'' for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+\subsubsection*{2. Basic Permissions.}
+
+\noindent\indent
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+\subsubsection*{3. Protecting Users' Legal Rights From
+Anti-Circumvention Law.}
+
+\noindent\indent
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+\subsubsection*{4. Conveying Verbatim Copies.}
+
+\noindent\indent
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+\subsubsection*{5. Conveying Modified Source Versions.}
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    ``keep intact all notices''.
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+``aggregate'' if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+\subsubsection*{6. Conveying Non-Source Forms.}
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A ``User Product'' is either (1) a ``consumer product'', which means
+any tangible personal property which is normally used for personal,
+family, or household purposes, or (2) anything designed or sold for
+incorporation into a dwelling.  In determining whether a product is a
+consumer product, doubtful cases shall be resolved in favor of coverage.
+For a particular product received by a particular user, ``normally
+used'' refers to a typical or common use of that class of product,
+regardless of the status of the particular user or of the way in which
+the particular user actually uses, or expects or is expected to use, the
+product.  A product is a consumer product regardless of whether the
+product has substantial commercial, industrial or non-consumer uses,
+unless such uses represent the only significant mode of use of the
+product.
+
+  ``Installation Information'' for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product
+from a modified version of its Corresponding Source.  The information
+must suffice to ensure that the continued functioning of the modified
+object code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to
+a network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+\subsubsection*{7. Additional Terms.}
+
+\noindent\indent
+  ``Additional permissions'' are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders
+of that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered ``further
+restrictions'' within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+\subsubsection*{8. Termination.}
+
+\noindent\indent
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+\subsubsection*{9. Acceptance Not Required for Having Copies.}
+
+\noindent\indent
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+\subsubsection*{10. Automatic Licensing of Downstream Recipients.}
+
+\noindent\indent
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An ``entity transaction'' is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+\subsubsection*{11. Patents.}
+
+\noindent\indent
+  A ``contributor'' is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's ``contributor version''.
+
+  A contributor's ``essential patent claims'' are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, ``control'' includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a ``patent license'' is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To ``grant'' such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  ``Knowingly relying'' means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is ``discriminatory'' if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+\subsubsection*{12. No Surrender of Others' Freedom.}
+
+\noindent\indent
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not convey it at all.  For example, if you agree to terms that
+obligate you to collect a royalty for further conveying from those to
+whom you convey the Program, the only way you could satisfy both those
+terms and this License would be to refrain entirely from conveying the
+Program.
+
+\subsubsection*{13. Use with the GNU Affero General Public License.}
+
+\noindent\indent
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+\subsubsection*{14. Revised Versions of this License.}
+
+\noindent\indent
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License ``or any later version'' applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+\subsubsection*{15. Disclaimer of Warranty.}
+
+\noindent\indent
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
+OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU
+ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+\subsubsection*{16. Limitation of Liability.}
+
+\noindent\indent
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
+CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
+NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES
+SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE
+WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+\subsubsection*{17. Interpretation of Sections 15 and 16.}
+
+\noindent\indent
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+\section*{END OF TERMS AND CONDITIONS}
+
+\newpage
+
+\section*{How to Apply These Terms to Your New Programs}
+
+\noindent\indent
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+
+\begin{verbatim}
+<one line to give the program's name and a brief idea of what it does.>
+Copyright (C) <year>  <name of author>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+\end{verbatim}
+
+\noindent
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+\begin{verbatim}
+<program>  Copyright (C) <year>  <name of author>
+This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+\end{verbatim}
+
+\noindent
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, your
+program's commands might be different; for a GUI interface, you would
+use an ``about box''.
+
+  You should also get your employer (if you work as a programmer) or
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary. For more information on this, and how to apply and follow the
+GNU GPL, see \verb|<http://www.gnu.org/licenses/>|.
+
+  The GNU General Public License does not permit incorporating your
+program into proprietary programs.  If your program is a subroutine
+library, you may consider it more useful to permit linking proprietary
+applications with the library.  If this is what you want to do, use the
+GNU Lesser General Public License instead of this License.  But first,
+please read \verb|<http://www.gnu.org/philosophy/why-not-lgpl.html>|.
+
+\end{footnotesize}
+
+%* eof *%
Index: deps/glpk/doc/glpk_faq.txt
===================================================================
--- deps/glpk/doc/glpk_faq.txt	(revision 9)
+++ deps/glpk/doc/glpk_faq.txt	(revision 9)
@@ -0,0 +1,435 @@
+
+GNU Linear Programming Kit FAQ
+
+  Summary: Frequently Asked Questions about the GNU Linear Programming Kit
+
+  Author: Dr. Harley Mackenzie <hjm@hardsoftware.com>                     
+
+  Posting-Frequency: Monthly                                              
+
+  Language: English                                                       
+
+  $Date: 2004/01/09 05:57:57 $                                            
+
+  $Revision: 1.6 $                                                        
+
+
+
+Introduction
+
+  Q. What is GPLK?                                                        
+
+  A. GLPK stands for the GNU Linear Programming Kit. The GLPK package is  
+  a set of routines written in ANSI C and organized in the form of a      
+  callable library. This package is intended for solving large-scale      
+  linear programming (LP), mixed integer linear programming (MIP), and    
+  other related problems.                                                 
+
+  The GLPK package includes the following main components:                
+
+    * implementation of the simplex method,                                   
+
+    * implementation of the primal-dual interior point method,                
+
+    * implementation of the branch-and-bound method,                          
+
+    * application program interface (API),                                    
+
+    * GNU MathProg modeling language (a subset of AMPL),                      
+
+    * GLPSOL, a stand-alone LP/MIP solver.                                    
+
+
+  Q. Who develops and maintains GLPK?                                     
+
+  A. GLPK is currently developed and maintained by Andrew Makhorin,       
+  Department for Applied Informatics, Moscow Aviation Institute, Moscow,  
+  Russia. Andrew's email address is <mao@mai2.rcnet.ru> and his postal    
+  address is 125871, Russia, Moscow, Volokolamskoye sh., 4, Moscow        
+  Aviation Institute, Andrew O. Makhorin                                  
+
+
+  Q. How is GLPK licensed?                                                
+
+  A. GLPK is currently licensed under the GNU General Public License      
+  (GPL). GLPK is free software; you can redistribute it and/or modify it  
+  under the terms of the GNU General Public License as published by the   
+  Free Software Foundation; either version 2, or (at your option) any     
+  later version.                                                          
+
+  GLPK is not licensed under the Lesser General Public License (LGPL) as  
+  distinct from other free LP codes such as lp_solve. The most            
+  significant implication is that code that is linked to the GLPK library 
+  must be released under the GPL, whereas with the LGPL, code linked to   
+  the library does not have to be released under the same license.        
+
+
+  Q. Where is the GLPK home page?                                         
+
+  The GLPK home page is part of the GNU web site and can found at         
+  <http://www.gnu.org/software/glpk/glpk.html>.                           
+
+
+  Q. How do I download and install GLPK?                                  
+
+  A. The GLPK source distribution can be found in the subdirectory        
+  /gnu/glpk/ on your favorite GNU mirror                                  
+  <http://www.gnu.org/prep/ftp.html> and can be compiled directly from    
+  the source.                                                             
+
+  The GLPK package (like all other GNU software) is distributed in the    
+  form of packed archive. This is one file named 'glpk-x.y.tar.gz', where 
+  x is the major version number and y is the minor version number.        
+
+  In order to prepare the distribution for installation you should:       
+
+    1. Copy the GLPK distribution file to some subdirectory.                   
+
+    2. Enter the command 'gzip -d glpk-x.y.tar.gz' in order to unpack the      
+       distribution file. After unpacking the name of the distribution file    
+       will be automatically changed to 'glpk-x.y.tar'.                        
+
+    3. Enter the command 'tar -x < glpk-x.y.tar' in order to unarchive the     
+       distribution. After this operation the subdirectory 'glpk-x.y' which is 
+       the GLPK distribution will have been automatically created.             
+
+  After you have unpacked and unarchived GLPK distribution you should     
+  configure the package, and compiled the application. The result of      
+  compilation is:                                                         
+
+    * the file 'libglpk.a', which is a library archive containing object code 
+      for all GLPK routines; and                                              
+
+    * the program 'glpsol', which is a stand-alone LP/MIP solver.             
+
+  Complete compilation and installation instructions are included in the  
+  INSTALL file included with the distribution.                            
+
+  The distribution includes make files for the Microsoft Visual C/C++     
+  version 6 and Borland C/C++ version 5 and by default compiles and links 
+  a glpk*.lib library file, a glpk*.dll DLL file and an glpsol.exe        
+  application file. A GNU Windows 4.1 binary, source and documentation    
+  compiled using the mingw32 C/C++ compiler is also available from        
+  <http://gnuwin32.sourceforge.net/packages/glpk.htm>.                    
+
+
+  Q. Is there a GLPK mailing list or newsgroup?                           
+
+  A. GLPK has two mailing lists: <help-glpk@gnu.org> and                  
+  <bug-glpk@gnu.org>.                                                     
+
+  The main discussion list is <help-glpk@gnu.org>, and is used to discuss 
+  all aspects of GLPK, including its development and porting. There is    
+  also a special list used for reporting bugs at <bug-glpk@gnu.org>.      
+
+  To subscribe to any GLPK mailing list, send an empty mail with a        
+  Subject: header line of just "subscribe" to the relevant -request list. 
+  For example, to subscribe yourself to the main list, you would send     
+  mail to <help-glpk-request@gnu.org> with no body and a Subject: header  
+  line of just "subscribe".                                               
+
+  Another way to subscribe to the GLP mailing lists is to visit the web   
+  pages <http://mail.gnu.org/mailman/listinfo/help-glpk> and              
+  <http://mail.gnu.org/mailman/listinfo/bug-glpk>.                        
+
+  Currently there are no newsgroups dedicated to GLPK.                    
+
+
+  Q. Who maintains this FAQ and how do I contribute to this FAQ?          
+
+  A. The present maintainer of this FAQ is Dr. Harley Mackenzie, HARD     
+  software, although the content of the FAQ is derived from many sources  
+  such as GLPK documentation, GLPK email archives and original content.   
+
+  Harley's email address is <hjm@hardsoftware.com> and his postal address 
+  is c/o HARD software, PO Box 8004, Newtown, Victoria 3220, Australia.   
+
+  All contributions to this FAQ, such as questions and (preferably)       
+  answers should be sent to the <hjm@hardsoftware.com> email address.     
+  This FAQ is copyright Harley Mackenzie 2003 and is released under the   
+  same license, terms and conditions as GLPK, that is, GPL version 2 or   
+  later.                                                                  
+
+  Contributions are not directly referenced in the body of the FAQ as     
+  this would become unmanageable and messy, but rather as a list of       
+  contributors to this FAQ. If you are the author of any information      
+  included in this FAQ and you do not want your content to be included,   
+  please contact the FAQ maintainer and your material will be removed.    
+  Also if you have not been correctly included as a contributor to this   
+  FAQ, your details have changed, or you do not want your name listed in  
+  the list of contributors, please contact the FAQ maintainer for         
+  correction.                                                             
+
+
+  Q. Where can I download this FAQ?                                       
+
+  The latest version of the GLPK FAQ is available to download from        
+  <http://www.hardsoftware.com/downloads.php#GLPK+FAQ> in the following   
+  formats:                                                                
+
+    * DocBook                                                                 
+
+    * Formatted text                                                          
+
+    * Adobe PDF                                                               
+
+
+  Q. Who are the FAQ contributors?                                        
+
+  A. The FAQ contents were created from the following sources:            
+
+    * Michael Hennebry                                                        
+
+    * http://www-unix.mcs.anl.gov/otc/Guide/faq/linear-programming-faq.html   
+
+    * Harley Mackenzie, HARD software Pty. Ltd.                               
+
+    * Andrew Makhorin, Department for Applied Informatics, Moscow Aviation    
+      Institute                                                               
+
+
+GLPK functions & features
+
+  Q. What is the current state of GLPK development?                       
+
+  A. GLPK is a work in progress and is presently under continual          
+  development. As of the current version 4.3, GLPK is a simplex-based     
+  solver is able to handle problems with up to 100,000 constraints. In    
+  particular, it successfully solves all instances from netlib (see the   
+  file bench.txt included in the GLPK distribution). The interior-point   
+  solver is not very robust as it is unable to handle dense columns,      
+  sometimes terminates due to numeric instability or slow convergence.    
+
+  The Mixed Integer Programming (MIP) solver currently is based on        
+  branch-and-bound, so it is unable to solve hard or very large problems  
+  with a probable practical limit of 100-200 integer variables. However,  
+  sometimes it is able to solve larger problems of up to 1000 integer     
+  variables, although the size that depends on properties of particular   
+  problem.                                                                
+
+
+  Q. How does GLPK compare with other LP codes?                           
+
+  A. I think that on very large-scale instances CPLEX 8.0 dual simplex is 
+  10-100 times faster than the GLPK simplex solver and, of course, much   
+  more robust. In many cases GLPK is faster and more robust than lp_solve 
+  4.0 for pure LPs as well as MIP's. See the bench.txt file in the GLPK   
+  distribution doc directory for GLPK netlib benchmark results.           
+
+  You can find benchmarks for some LP and MIP solvers such as CPLEX,      
+  GLPK, lp_solve, and OSL on Hans Mittelmann's webpage at                 
+  <http://plato.asu.edu/bench.html>.                                      
+
+
+  Q. What are the differences between AMPL and GNU MathProg?              
+
+  A. The subset of AMPL implemented in MathProg approximately corresponds 
+  to AMPL status in 1990, because it is mainly based on the paper Robert  
+  Fourer, David M Gay and Brian W Kernighan (1990), "A Modeling Language  
+  for Mathematical Programming", Management Science, Vol 36, pp. 519-554  
+  and is available at                                                     
+  <http://users.iems.nwu.edu/~4er/WRITINGS/amplmod.pdf>.                  
+
+  The GNU MathProg translator was developed as part of GLPK. However, GNU 
+  MathProg can be easily used in other applications as there is a set of  
+  MathProg interface routines designed for use in other applications.     
+
+
+  Q. What input file formats does GLPK support?                           
+
+  A. GLPK presently can read input and output LP model files in three     
+  supported formats:                                                      
+
+    * MPS format - which is a column oriented and widely supported file       
+      format but has poor human readability.                                  
+
+    * CPLEX format - which is an easily readable row oriented format.         
+
+    * GNU MathProg - which is an AMPL like mathematical modeling language.    
+
+
+  Q. What interfaces are available for GLPK?                              
+
+  A. The GLPK package is in fact a C API that can be either by statically 
+  or dynamically linked directly with many programming systems.           
+
+  Presently there are three contributed external interfaces included with 
+  the GLPK package:                                                       
+
+    * GLPK Java Native Interface (JNI)                                        
+
+    * GLPK Delphi Interface (DELI)                                            
+
+    * GLPKMEX Matlab MEX interface                                            
+
+  There is an unofficial Microsoft Visual Basic, Tcl/Tk and Java GLPK     
+  interface available at                                                  
+  <http://gottfried.lindner.bei.t-online.de/glpk.htm>.                    
+
+  There are other language interfaces under development, including a Perl 
+  interface currently being developed by the FAQ maintainer, Dr. Harley   
+  Mackenzie <hjm@hardsoftware.com>.                                       
+
+
+  Q. Where can I find some examples?                                      
+
+  A. The GLPK package distribution contains many examples written in GNU  
+  MathProg (*.mod), C API calls (*.c), CPLEX input file format (*.lpt),   
+  MPS format (*.mps) as well as some specific Traveling Salesman examples 
+  (*.tsp).                                                                
+
+  All of the examples can be found in the GLPK distribution examples      
+  sub-directory.                                                          
+
+
+  Q. What are the future plans for GLPK?                                  
+
+  A. Developments planned for GLPK include improving the existing key     
+  GLPK components, such as developing a more robust and more efficient    
+  implementation of the simplex-based and interior-point solvers. Future  
+  GLPK enhancements planned are implementing a branch-and-cut solver, a   
+  MIP pre-processor, post-optimal and sensitivity analysis and possibly   
+  network simplex and quadratic programming solvers.                      
+
+
+  Q. How do I report a GLPK bug?                                          
+
+  A. If you think you have found a bug in GLPK, then you should send as   
+  complete a report as possible to <bug-glpk@gnu.org>.                    
+
+
+  Q. How do I contribute to the GLPK development?                         
+
+  A. At present new GLPK development patches should be emailed to Andrew  
+  Makhorin <mao@mai2.rcnet.ru >, with sufficient documentation and test   
+  code to explain the nature of the patch, how to install it and the      
+  implications of its use. Before commencing any major GLPK development   
+  for inclusion in the GLPK distribution, it would be a good idea to      
+  discuss the idea on the GLPK mailing list.                              
+
+
+  Q. How do I compile and link a GLPK application on a UNIX platform?     
+
+  A. To compile a GLPK application on a UNIX platform, then compiler must 
+  be able to include the GLPK include files and link to the GLPK library. 
+  For example, on a system where the GLPK system is installed:            
+
+  gcc mylp.c -o mylp -lglpk                                               
+
+  or specify the include files and libglpk.a explicitly, if GLPK is not   
+  installed.                                                              
+
+
+  Q. How do I compile and link a GLPK application on a Win32 platform?    
+
+  A. On a Win32 platform, GLPK is implemented either as a Win32 Dynamic   
+  Link Library (DLL) or can be statically linked to the glpk*.lib file.   
+  As with the UNIX instructions, a GLPK application must set a path to    
+  the GLPK include files and also reference the GLPK library if           
+  statically linked.                                                      
+
+
+  Q. How do I limit the GLPK execution time?                              
+
+  A. You can limit the computing time by setting the control parameter    
+  LPX_K_TMLIM via the API routine lpx_set_real_parm . At present there is 
+  no way of limiting the execution time of glpsol without changing the    
+  source and recompiling a specific version.                              
+
+
+GLPK Linear Programming
+
+  Q. What is Linear Programming and how does it work?                     
+
+  A. Linear Programming is a mathematical technique that is a generic     
+  method for solving certain systems of equations with linear terms. The  
+  real power of LP's are that they have many practical applications and   
+  have proven to be a powerful and robust tool.                           
+
+  The best single source of information on LP's is the Linear Programming 
+  FAQ                                                                     
+  <http://www-unix.mcs.anl.gov/otc/Guide/faq/linear-programming-faq.html> 
+  that has information on LP's and MIP's, includes a comprehensive list   
+  of available LP software and has many LP references for further study.  
+
+
+  Q. How do I determine the stability of an LP solution?                  
+
+  A. You can perform sensitivity analysis by specifying the --bounds      
+  option for glpsol as:                                                   
+
+  glpsol ... --bounds filename                                            
+
+  in which case the solver writes results of the analysis to the          
+  specified filename in plain text format. The corresponding API routine  
+  is lpx_print_sens_bnds() .                                              
+
+
+  Q. How do I determine which constraints are causing infeasibility?      
+
+  A straightforward way to find such a set of constraints is to drop      
+  constraints one at a time. If dropping a constraint results in a        
+  solvable problem, pick it up and go on to the next constraint. After    
+  applying phase 1 to an infeasible problem, all basic satisfied          
+  constraints may be dropped.                                             
+
+  If the problem has a feasible dual, then running the dual simplex       
+  method is a more direct approach. After the last pivot, the nonbasic    
+  constraints and one of the violated constraints will constitute a       
+  minimal set. The GLPK simplex table routines will allow you to pick a   
+  correct constraint from the violated ones.                              
+
+  Note that the GLPK pre-solver needs to be turned off for the preceding  
+  technique to work, otherwise GLPK does not keep the basis of an         
+  infeasible solution.                                                    
+
+  Also a more detailed methodology has been posted on the mail list       
+  archive at                                                              
+  <http://mail.gnu.org/archive/html/help-glpk/2003-09/msg00017.html>.     
+
+
+  Q. What is the difference between checks and constraints?               
+
+  A. Check statements are intended to check that all data specified by    
+  the user of the model are correct, mainly in the data section of a      
+  MathProg model. For example, if some parameter means the number of      
+  nodes in a network, it must be positive integer, that is just the       
+  condition to be checked in the check statement (although in this case   
+  such condition may be also checked directly in the parameter            
+  statement). Note that check statements are performed when the           
+  translator is generating the model, so they cannot include variables.   
+
+  Constraints are conditions that are expressed in terms of variables and 
+  resolved by the solver after the model has been completely generated.   
+  If all data specified in the model are correct a priori, check          
+  statements are not needed and can be omitted, while constraints are     
+  essential components of the model and therefore cannot be omitted.      
+
+
+GLPK Integer Programming 
+
+  Q. What is Integer Programming and how does it work?                    
+
+  A. Integer LP models are ones whose variables are constrained to take   
+  integer or whole number (as opposed to fractional) values. It may not   
+  be obvious that integer programming is a very much harder problem than  
+  ordinary linear programming, but that is nonetheless the case, in both  
+  theory and practice.                                                    
+
+
+  Q. What is the Integer Optimization Suite (IOS)?                        
+
+  A. IOS is a framework to implement implicit enumeration methods based   
+  on LP relaxation (like branch-and-bound and branch-and-cut). Currently  
+  IOS includes only basic features (the enumeration tree, API routines,   
+  and the driver) and is not completely documented.                       
+
+
+  Q. I have just changed an LP to a MIP and now it doesn't work?          
+
+  A. If you have an existing LP that is working and you change to an MIP  
+  and receive a "lpx_integer: optimal solution of LP relaxation required" 
+  204 (==LPX_E_FAULT) error, you probably have not called the LP solution 
+  method lpx_simplex() before lpx_integer() . The MIP routines use the LP 
+  solution as part of the MIP solution methodology.                       
+
Index: deps/glpk/doc/gmpl.tex
===================================================================
--- deps/glpk/doc/gmpl.tex	(revision 9)
+++ deps/glpk/doc/gmpl.tex	(revision 9)
@@ -0,0 +1,4653 @@
+%* gmpl.tex *%
+
+%***********************************************************************
+%  This code is part of GLPK (GNU Linear Programming Kit).
+%
+%  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+%  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+%  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+%  E-mail: <mao@gnu.org>.
+%
+%  GLPK is free software: you can redistribute it and/or modify it
+%  under the terms of the GNU General Public License as published by
+%  the Free Software Foundation, either version 3 of the License, or
+%  (at your option) any later version.
+%
+%  GLPK is distributed in the hope that it will be useful, but WITHOUT
+%  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+%  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+%  License for more details.
+%
+%  You should have received a copy of the GNU General Public License
+%  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+%***********************************************************************
+
+\documentclass[10pt]{article}
+\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue]{hyperref}
+
+\begin{document}
+
+\thispagestyle{empty}
+
+\begin{center}
+
+\vspace*{1in}
+
+\begin{huge}
+\sf\bfseries Modeling Language GNU MathProg
+\end{huge}
+
+\vspace{0.5in}
+
+\begin{LARGE}
+\sf Language Reference
+\end{LARGE}
+
+\vspace{0.5in}
+
+\begin{LARGE}
+\sf for GLPK Version 4.45
+\end{LARGE}
+
+\vspace{0.5in}
+\begin{Large}
+\sf (DRAFT, December 2010)
+\end{Large}
+
+\end{center}
+
+\newpage
+
+\vspace*{1in}
+
+\vfill
+
+\noindent
+The GLPK package is part of the GNU Project released under the aegis of
+GNU.
+
+\medskip\noindent
+Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+
+\medskip\noindent
+Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+MA 02110-1301, USA.
+
+\medskip\noindent
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+\medskip\noindent
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that
+the entire resulting derived work is distributed under the terms of
+a permission notice identical to this one.
+
+\medskip\noindent
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions.
+
+\newpage
+
+\tableofcontents
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Introduction}
+
+{\it GNU MathProg} is a modeling language intended for describing
+linear mathematical programming models.\footnote{The GNU MathProg
+language is a subset of the AMPL language. Its GLPK implementation is
+mainly based on the paper: {\it Robert Fourer}, {\it David M. Gay}, and
+{\it Brian W. Kernighan}, ``A Modeling Language for Mathematical
+Programming.'' {\it Management Science} 36 (1990)\linebreak pp. 519-54.}
+
+Model descriptions written in the GNU MathProg language consist of
+a set of statements and data blocks constructed by the user from the
+language elements described in this document.
+
+In a process called {\it translation}, a program called the {\it model
+translator} analyzes the model description and translates it into
+internal data structures, which may be then used either for generating
+mathematical programming problem instance or directly by a program
+called the {\it solver} to obtain numeric solution of the problem.
+
+\subsection{Linear programming problem}
+\label{problem}
+
+In MathProg the linear programming (LP) problem is stated as follows:
+
+\medskip
+
+\noindent\hspace{.7in}minimize (or maximize)
+$$z=c_1x_1+c_2x_2+\dots+c_nx_n+c_0\eqno(1.1)$$
+\noindent\hspace{.7in}subject to linear constraints
+$$
+\begin{array}{l@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }l}
+L_1&\leq&a_{11}x_1&+&a_{12}x_2&+\dots+&a_{1n}x_n&\leq&U_1\\
+L_2&\leq&a_{21}x_1&+&a_{22}x_2&+\dots+&a_{2n}x_n&\leq&U_2\\
+\multicolumn{9}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
+L_m&\leq&a_{m1}x_1&+&a_{m2}x_2&+\dots+&a_{mn}x_n&\leq&U_m\\
+\end{array}\eqno(1.2)
+$$
+\noindent\hspace{.7in}and bounds of variables
+$$
+\begin{array}{l@{\ }c@{\ }c@{\ }c@{\ }l}
+l_1&\leq&x_1&\leq&u_1\\
+l_2&\leq&x_2&\leq&u_2\\
+\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .}\\
+l_n&\leq&x_n&\leq&u_n\\
+\end{array}\eqno(1.3)
+$$
+where $x_1$, $x_2$, \dots, $x_n$ are variables; $z$ is the objective
+function; $c_1$, $c_2$, \dots, $c_n$ are objective coefficients; $c_0$
+is the constant term (``shift'') of the objective function; $a_{11}$,
+$a_{12}$, \dots, $a_{mn}$ are constraint coefficients; $L_1$, $L_2$,
+\dots, $L_m$ are lower constraint bounds; $U_1$, $U_2$, \dots, $U_m$
+are upper constraint bounds; $l_1$, $l_2$, \dots, $l_n$ are lower
+bounds of variables; $u_1$, $u_2$, \dots, $u_n$ are upper bounds of
+variables.
+
+Bounds of variables and constraint bounds can be finite as well as
+infinite. Besides, lower bounds can be equal to corresponding upper
+bounds. Thus, the following types of variables and constraints are
+allowed:
+
+\newpage
+
+\begin{tabular}{@{}r@{\ }c@{\ }c@{\ }c@{\ }l@{\hspace*{38pt}}l}
+$-\infty$&$<$&$x$&$<$&$+\infty$&Free (unbounded) variable\\
+$l$&$\leq$&$x$&$<$&$+\infty$&Variable with lower bound\\
+$-\infty$&$<$&$x$&$\leq$&$u$&Variable with upper bound\\
+$l$&$\leq$&$x$&$\leq$&$u$&Double-bounded variable\\
+$l$&$=$&$x$&=&$u$&Fixed variable\\
+\end{tabular}
+
+\bigskip
+
+\begin{tabular}{@{}r@{\ }c@{\ }c@{\ }c@{\ }ll}
+$-\infty$&$<$&$\sum a_jx_j$&$<$&$+\infty$&Free (unbounded) linear
+form\\
+$L$&$\leq$&$\sum a_jx_j$&$<$&$+\infty$&Inequality constraint ``greater
+than or equal to''\\
+$-\infty$&$<$&$\sum a_jx_j$&$\leq$&$U$&Inequality constraint ``less
+than or equal to''\\
+$L$&$\leq$&$\sum a_jx_j$&$\leq$&$U$&Double-bounded inequality
+constraint\\
+$L$&$=$&$\sum a_jx_j$&=&$U$&Equality constraint\\
+\end{tabular}
+
+\bigskip
+
+In addition to pure LP problems MathProg also allows mixed integer
+linear programming (MIP) problems, where some or all variables are
+restricted to be integer or binary.
+
+\subsection{Model objects}
+
+In MathProg the model is described in terms of sets, parameters,
+variables, constraints, and objectives, which are called {\it model
+objects}.
+
+The user introduces particular model objects using the language
+statements. Each model object is provided with a symbolic name that
+uniquely identifies the object and is intended for referencing purposes.
+
+Model objects, including sets, can be multidimensional arrays built
+over indexing sets. Formally, $n$-dimensional array $A$ is the mapping:
+$$A:\Delta\rightarrow\Xi,\eqno(1.4)$$
+where $\Delta\subseteq S_1\times\dots\times S_n$ is a subset of the
+Cartesian product of indexing sets,\linebreak $\Xi$ is a set of array members.
+In MathProg the set $\Delta$ is called the {\it subscript domain}. Its
+members are $n$-tuples $(i_1,\dots,i_n)$, where $i_1\in S_1$, \dots,
+$i_n\in S_n$.
+
+If $n=0$, the Cartesian product above has exactly one member (namely,
+\linebreak 0-tuple), so it is convenient to think scalar objects as
+0-dimensional arrays having one member.
+
+The type of array members is determined by the type of corresponding
+model object as follows:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}ll@{}}
+Model object&Array member\\
+\hline
+Set&Elemental plain set\\
+Parameter&Number or symbol\\
+Variable&Elemental variable\\
+Constraint&Elemental constraint\\
+Objective&Elemental objective\\
+\end{tabular}
+
+\medskip
+
+In order to refer to a particular object member the object should be
+provided with {\it subscripts}. For example, if $a$ is a 2-dimensional
+parameter defined over $I\times J$, a reference to its particular
+member can be written as $a[i,j]$, where $i\in I$ and $j\in J$. It is
+understood that scalar objects being 0-dimensional need no subscripts.
+
+\subsection{Structure of model description}
+
+It is sometimes desirable to write a model which, at various points,
+may require different data for each problem instance to be solved using
+that model. For this reason in MathProg the model description consists
+of two parts: the {\it model section} and the {\it data section}.
+
+The model section is a main part of the model description that contains
+declarations of model objects and is common for all problems based on
+the corresponding model.
+
+The data section is an optional part of the model description that
+contains data specific for a particular problem instance.
+
+Depending on what is more convenient the model and data sections can be
+placed either in one file or in two separate files. The latter feature
+allows having arbitrary number of different data sections to be used
+with the same model section.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Coding model description}
+\label{coding}
+
+The model description is coded in plain text format using ASCII
+character set. Characters valid in the model description are the
+following:
+
+\begin{itemize}
+\item alphabetic characters:\\
+\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|\\
+\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 _|
+\item numeric characters:\\
+\verb|0 1 2 3 4 5 6 7 8 9|
+\item special characters:\\
+\verb?! " # & ' ( ) * + , - . / : ; < = > [ ] ^ { | }?
+\item white-space characters:\\
+\verb|SP HT CR NL VT FF|
+\end{itemize}
+
+Within string literals and comments any ASCII characters (except
+control characters) are valid.
+
+White-space characters are non-significant. They can be used freely
+between lexical units to improve readability of the model description.
+They are also used to separate lexical units from each other if there
+is no other way to do that.
+
+Syntactically model description is a sequence of lexical units in the
+following categories:
+
+\begin{itemize}
+\item symbolic names;
+\item numeric literals;
+\item string literals;
+\item keywords;
+\item delimiters;
+\item comments.
+\end{itemize}
+
+The lexical units of the language are discussed below.
+
+\subsection{Symbolic names}
+
+A {\it symbolic name} consists of alphabetic and numeric characters,
+the first of which must be alphabetic. All symbolic names are distinct
+(case sensitive).
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|alpha123|
+
+\noindent\verb|This_is_a_name|
+
+\noindent\verb|_P123_abc_321|
+
+\newpage
+
+Symbolic names are used to identify model objects (sets, parameters,
+variables, constraints, objectives) and dummy indices.
+
+All symbolic names (except names of dummy indices) must be unique, i.e.
+the model description must have no objects with identical names.
+Symbolic names of dummy indices must be unique within the scope, where
+they are valid.
+
+\subsection{Numeric literals}
+
+A {\it numeric literal} has the form {\it xx}{\tt E}{\it syy}, where
+{\it xx} is a number with optional decimal point, {\it s} is the sign
+{\tt+} or {\tt-}, {\it yy} is a decimal exponent. The letter {\tt E} is
+case insensitive and can be coded as {\tt e}.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|123|
+
+\noindent\verb|3.14159|
+
+\noindent\verb|56.E+5|
+
+\noindent\verb|.78|
+
+\noindent\verb|123.456e-7|
+
+\medskip
+
+Numeric literals are used to represent numeric quantities. They have
+obvious fixed meaning.
+
+\subsection{String literals}
+
+A {\it string literal} is a sequence of arbitrary characters enclosed
+either in single quotes or in double quotes. Both these forms are
+equivalent.
+
+If the single quote is part of a string literal enclosed in single
+quotes, it must be coded twice. Analogously, if the double quote is
+part of a string literal enclosed in double quotes, it must be coded
+twice.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|'This is a string'|
+
+\noindent\verb|"This is another string"|
+
+\noindent\verb|'1 + 2 = 3'|
+
+\noindent\verb|'That''s all'|
+
+\noindent\verb|"She said: ""No"""|
+
+\medskip
+
+String literals are used to represent symbolic quantities.
+
+\subsection{Keywords}
+
+A {\it keyword} is a sequence of alphabetic characters and possibly
+some special characters.
+
+All keywords fall into two categories: {\it reserved keywords}, which
+cannot be used as symbolic names, and {\it non-reserved keywords},
+which being recognized by context can be used as symbolic names.
+
+\newpage
+
+The reserved keywords are the following:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}p{.7in}p{.7in}p{.7in}p{.7in}@{}}
+{\tt and}&{\tt else}&{\tt mod}&{\tt union}\\
+{\tt by}&{\tt if}&{\tt not}&{\tt within}\\
+{\tt cross}&{\tt in}&{\tt or}\\
+{\tt diff}&{\tt inter}&{\tt symdiff}\\
+{\tt div}&{\tt less}&{\tt then}\\
+\end{tabular}
+
+\medskip
+
+Non-reserved keywords are described in following sections.
+
+All the keywords have fixed meaning, which will be explained on
+discussion of corresponding syntactic constructions, where the keywords
+are used.
+
+\subsection{Delimiters}
+
+A {\it delimiter} is either a single special character or a sequence of
+two special characters as follows:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}p{.3in}p{.3in}p{.3in}p{.3in}p{.3in}p{.3in}@{}}
+{\tt+}&{\tt\textasciicircum}&{\tt==}&{\tt!}&{\tt:}&{\tt)}\\
+{\tt-}&{\tt\&}&{\tt>=}&{\tt\&\&}&{\tt;}&{\tt[}\\
+{\tt*}&{\tt<}&{\tt>}&{\tt||}&{\tt:=}&{\tt|}\\
+{\tt/}&{\tt<=}&{\tt<>}&{\tt.}&{\tt..}&{\tt\{}\\
+{\tt**}&{\tt=}&{\tt!=}&{\tt,}&{\tt(}&{\tt\}}\\
+\end{tabular}
+
+\medskip
+
+If the delimiter consists of two characters, there must be no spaces
+between the characters.
+
+All the delimiters have fixed meaning, which will be explained on
+discussion corresponding syntactic constructions, where the delimiters
+are used.
+
+\subsection{Comments}
+
+For documenting purposes the model description can be provided with
+{\it comments}, which may have two different forms. The first form is
+a {\it single-line comment}, which begins with the character {\tt\#}
+and extends until end of line. The second form is a {\it comment
+sequence}, which is a sequence of any characters enclosed within
+{\tt/*} and {\tt*/}.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|param n := 10; # This is a comment|
+
+\noindent\verb|/* This is another comment */|
+
+\medskip
+
+Comments are ignored by the model translator and can appear anywhere in
+the model description, where white-space characters are allowed.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Expressions}
+
+An {\it expression} is a rule for computing a value. In model
+description expressions are used as constituents of certain statements.
+
+In general case expressions consist of operands and operators.
+
+Depending on the type of the resultant value all expressions fall into
+the following categories:
+
+\begin{itemize}
+\item numeric expressions;
+\item symbolic expressions;
+\item indexing expressions;
+\item set expressions;
+\item logical expressions;
+\item linear expressions.
+\end{itemize}
+
+\subsection{Numeric expressions}
+
+A {\it numeric expression} is a rule for computing a single numeric
+value represented as a floating-point number.
+
+The primary numeric expression may be a numeric literal, dummy index,
+unsubscripted parameter, subscripted parameter, built-in function
+reference, iterated numeric expression, conditional numeric expression,
+or another numeric expression enclosed in parentheses.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent
+\begin{tabular}{@{}ll@{}}
+\verb|1.23|&(numeric literal)\\
+\verb|j|&(dummy index)\\
+\verb|time|&(unsubscripted parameter)\\
+\verb|a['May 2003',j+1]|&(subscripted parameter)\\
+\verb|abs(b[i,j])|&(function reference)\\
+\verb|sum{i in S diff T} alpha[i] * b[i,j]|&(iterated expression)\\
+\verb|if i in I then 2 * p else q[i+1]|&(conditional expression)\\
+\verb|(b[i,j] + .5 * c)|&(parenthesized expression)\\
+\end{tabular}
+
+\medskip
+
+More general numeric expressions containing two or more primary numeric
+expressions may be constructed by using certain arithmetic operators.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|j+1|
+
+\noindent\verb|2 * a[i-1,j+1] - b[i,j]|
+
+\noindent\verb|sum{j in J} a[i,j] * x[j] + sum{k in K} b[i,k] * x[k]|
+
+\noindent\verb|(if i in I then 2 * p else q[i+1]) / (a[i,j] + 1.5)|
+
+\subsubsection{Numeric literals}
+
+If the primary numeric expression is a numeric literal, the resultant
+value is obvious.
+
+\subsubsection{Dummy indices}
+
+If the primary numeric expression is a dummy index, the resultant value
+is current value assigned to that dummy index.
+
+\subsubsection{Unsubscripted parameters}
+
+If the primary numeric expression is an unsubscripted parameter (which
+must be 0-dimensional), the resultant value is the value of that
+parameter.
+
+\subsubsection{Subscripted parameters}
+
+The primary numeric expression, which refers to a subscripted parameter,
+has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
+
+\medskip
+
+\noindent where {\it name} is the symbolic name of the parameter,
+$i_1$, $i_2$, \dots, $i_n$ are subscripts.
+
+Each subscript must be a numeric or symbolic expression. The number of
+subscripts in the subscript list must be the same as the dimension of
+the parameter with which the subscript list is associated.
+
+Actual values of subscript expressions are used to identify
+a particular member of the parameter that determines the resultant
+value of the primary expression.
+
+\subsubsection{Function references}
+
+In MathProg there exist the following built-in functions which may be
+used in numeric expressions:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt abs(}$x${\tt)}&$|x|$, absolute value of $x$\\
+{\tt atan(}$x${\tt)}&$\arctan x$, principal value of the arc tangent of
+$x$ (in radians)\\
+{\tt atan(}$y${\tt,} $x${\tt)}&$\arctan y/x$, principal value of the
+arc tangent of $y/x$ (in radians). In this case the signs of both
+arguments $y$ and $x$ are used to determine the quadrant of the
+resultant value\\
+{\tt card(}$X${\tt)}&$|X|$, cardinality (the number of elements) of
+set $X$\\
+{\tt ceil(}$x${\tt)}&$\lceil x\rceil$, smallest integer not less than
+$x$ (``ceiling of $x$'')\\
+{\tt cos(}$x${\tt)}&$\cos x$, cosine of $x$ (in radians)\\
+{\tt exp(}$x${\tt)}&$e^x$, base-$e$ exponential of $x$\\
+{\tt floor(}$x${\tt)}&$\lfloor x\rfloor$, largest integer not greater
+than $x$ (``floor of $x$'')\\
+\end{tabular}
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt gmtime()}&the number of seconds elapsed since 00:00:00~Jan~1, 1970,
+Coordinated Universal Time (for details see Subsection \ref{gmtime},
+page \pageref{gmtime})\\
+{\tt length(}$s${\tt)}&$|s|$, length of character string $s$\\
+{\tt log(}$x${\tt)}&$\log x$, natural logarithm of $x$\\
+{\tt log10(}$x${\tt)}&$\log_{10}x$, common (decimal) logarithm of $x$\\
+{\tt max(}$x_1${\tt,} $x_2${\tt,} \dots{\tt,} $x_n${\tt)}&the largest
+of values $x_1$, $x_2$, \dots, $x_n$\\
+{\tt min(}$x_1${\tt,} $x_2${\tt,} \dots{\tt,} $x_n${\tt)}&the smallest
+of values $x_1$, $x_2$, \dots, $x_n$\\
+{\tt round(}$x${\tt)}&rounding $x$ to nearest integer\\
+{\tt round(}$x${\tt,} $n${\tt)}&rounding $x$ to $n$ fractional decimal
+digits\\
+{\tt sin(}$x${\tt)}&$\sin x$, sine of $x$ (in radians)\\
+{\tt sqrt(}$x${\tt)}&$\sqrt{x}$, non-negative square root of $x$\\
+{\tt str2time(}$s${\tt,} $f${\tt)}&converting character string $s$ to
+calendar time (for details see Subsection \ref{str2time}, page
+\pageref{str2time})\\
+{\tt trunc(}$x${\tt)}&truncating $x$ to nearest integer\\
+{\tt trunc(}$x${\tt,} $n${\tt)}&truncating $x$ to $n$ fractional
+decimal digits\\
+{\tt Irand224()}&generating pseudo-random integer uniformly distributed
+in $[0,2^{24})$\\
+{\tt Uniform01()}&generating pseudo-random number uniformly distributed
+in $[0,1)$\\
+{\tt Uniform(}$a${\tt,} $b${\tt)}&generating pseudo-random number
+uniformly distributed in $[a,b)$\\
+{\tt Normal01()}&generating Gaussian pseudo-random variate with
+$\mu=0$ and $\sigma=1$\\
+{\tt Normal(}$\mu${\tt,} $\sigma${\tt)}&generating Gaussian
+pseudo-random variate with given $\mu$ and $\sigma$\\
+\end{tabular}
+
+\medskip
+
+Arguments of all built-in functions, except {\tt card}, {\tt length},
+and {\tt str2time}, must be numeric expressions. The argument of
+{\tt card} must be a set expression. The argument of {\tt length} and
+both arguments of {\tt str2time} must be symbolic expressions.
+
+The resultant value of the numeric expression, which is a function
+reference, is the result of applying the function to its argument(s).
+
+Note that each pseudo-random generator function has a latent argument
+(i.e. some internal state), which is changed whenever the function has
+been applied. Thus, if the function is applied repeatedly even to
+identical arguments, due to the side effect different resultant values
+are always produced.
+
+\subsubsection{Iterated expressions}
+\label{itexpr}
+
+An {\it iterated numeric expression} is a primary numeric expression,
+which has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\it iterated-operator indexing-expression integrand}
+
+\medskip
+
+\noindent where {\it iterated-operator} is the symbolic name of the
+iterated operator to be performed (see below), {\it indexing-expression}
+is an indexing expression which introduces dummy indices and controls
+iterating, {\it integrand} is a numeric expression that participates in
+the operation.
+
+In MathProg there exist four iterated operators, which may be used in
+numeric expressions:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}lll@{}}
+{\tt sum}&summation&$\displaystyle\sum_{(i_1,\dots,i_n)\in\Delta}
+f(i_1,\dots,i_n)$\\
+{\tt prod}&production&$\displaystyle\prod_{(i_1,\dots,i_n)\in\Delta}
+f(i_1,\dots,i_n)$\\
+{\tt min}&minimum&$\displaystyle\min_{(i_1,\dots,i_n)\in\Delta}
+f(i_1,\dots,i_n)$\\
+{\tt max}&maximum&$\displaystyle\max_{(i_1,\dots,i_n)\in\Delta}
+f(i_1,\dots,i_n)$\\
+\end{tabular}
+
+\medskip
+
+\noindent where $i_1$, \dots, $i_n$ are dummy indices introduced in
+the indexing expression, $\Delta$ is the domain, a set of $n$-tuples
+specified by the indexing expression which defines particular values
+assigned to the dummy indices on performing the iterated operation,
+$f(i_1,\dots,i_n)$ is the integrand, a numeric expression whose
+resultant value depends on the dummy indices.
+
+The resultant value of an iterated numeric expression is the result of
+applying of the iterated operator to its integrand over all $n$-tuples
+contained in the domain.
+
+\subsubsection{Conditional expressions}
+\label{ifthen}
+
+A {\it conditional numeric expression} is a primary numeric expression,
+which has one of the following two syntactic forms:
+
+\medskip
+
+\noindent\hfil
+{\tt if} $b$ {\tt then} $x$ {\tt else} $y$
+
+\medskip
+
+\noindent\hspace{126.5pt}
+{\tt if} $b$ {\tt then} $x$
+
+\medskip
+
+\noindent where $b$ is an logical expression, $x$ and $y$ are numeric
+expressions.
+
+The resultant value of the conditional expression depends on the value
+of the logical expression that follows the keyword {\tt if}. If it
+takes on the value {\it true}, the value of the conditional expression
+is the value of the expression that follows the keyword {\tt then}.
+Otherwise, if the logical expression takes on the value {\it false},
+the value of the conditional expression is the value of the expression
+that follows the keyword {\it else}. If the second, reduced form of the
+conditional expression is used and the logical expression takes on the
+value {\it false}, the resultant value of the conditional expression is
+zero.
+
+\subsubsection{Parenthesized expressions}
+
+Any numeric expression may be enclosed in parentheses that
+syntactically makes it a primary numeric expression.
+
+Parentheses may be used in numeric expressions, as in algebra, to
+specify the desired order in which operations are to be performed.
+Where parentheses are used, the expression within the parentheses is
+evaluated before the resultant value is used.
+
+The resultant value of the parenthesized expression is the same as the
+value of the expression enclosed within parentheses.
+
+\subsubsection{Arithmetic operators}
+
+In MathProg there exist the following arithmetic operators, which may
+be used in numeric expressions:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt +} $x$&unary plus\\
+{\tt -} $x$&unary minus\\
+$x$ {\tt +} $y$&addition\\
+$x$ {\tt -} $y$&subtraction\\
+$x$ {\tt less} $y$&positive difference (if $x<y$ then 0 else $x-y$)\\
+$x$ {\tt *} $y$&multiplication\\
+$x$ {\tt /} $y$&division\\
+$x$ {\tt div} $y$&quotient of exact division\\
+$x$ {\tt mod} $y$&remainder of exact division\\
+$x$ {\tt **} $y$, $x$ {\tt\textasciicircum} $y$&exponentiation (raising
+to power)\\
+\end{tabular}
+
+\medskip
+
+\noindent where $x$ and $y$ are numeric expressions.
+
+If the expression includes more than one arithmetic operator, all
+operators are performed from left to right according to the hierarchy
+of operations (see below) with the only exception that the
+exponentiaion operators are performed from right to left.
+
+The resultant value of the expression, which contains arithmetic
+operators, is the result of applying the operators to their operands.
+
+\subsubsection{Hierarchy of operations}
+\label{hierarchy}
+
+The following list shows the hierarchy of operations in numeric
+expressions:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}ll@{}}
+Operation&Hierarchy\\
+\hline
+Evaluation of functions ({\tt abs}, {\tt ceil}, etc.)&1st\\
+Exponentiation ({\tt**}, {\tt\textasciicircum})&2nd\\
+Unary plus and minus ({\tt+}, {\tt-})&3rd\\
+Multiplication and division ({\tt*}, {\tt/}, {\tt div}, {\tt mod})&4th\\
+Iterated operations ({\tt sum}, {\tt prod}, {\tt min}, {\tt max})&5th\\
+Addition and subtraction ({\tt+}, {\tt-}, {\tt less})&6th\\
+Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
+7th\\
+\end{tabular}
+
+\medskip
+
+This hierarchy is used to determine which of two consecutive operations
+is performed first. If the first operator is higher than or equal to
+the second, the first operation is performed. If it is not, the second
+operator is compared to the third, etc. When the end of the expression
+is reached, all of the remaining operations are performed in the
+reverse order.
+
+\newpage
+
+\subsection{Symbolic expressions}
+
+A {\it symbolic expression} is a rule for computing a single symbolic
+value represented as a character string.
+
+The primary symbolic expression may be a string literal, dummy index,
+unsubscripted parameter, subscripted parameter, built-in function
+reference, conditional symbolic expression, or another symbolic
+expression enclosed in parentheses.
+
+It is also allowed to use a numeric expression as the primary symbolic
+expression, in which case the resultant value of the numeric expression
+is automatically converted to the symbolic type.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent
+\begin{tabular}{@{}ll@{}}
+\verb|'May 2003'|&(string literal)\\
+\verb|j|&(dummy index)\\
+\verb|p|&(unsubscripted parameter)\\
+\verb|s['abc',j+1]|&(subscripted parameter)\\
+\verb|substr(name[i],k+1,3)|&(function reference)\\
+\verb|if i in I then s[i,j] else t[i+1]|&(conditional expression)\\
+\verb|((10 * b[i,j]) & '.bis')|&(parenthesized expression)\\
+\end{tabular}
+
+\medskip
+
+More general symbolic expressions containing two or more primary
+symbolic expressions may be constructed by using the concatenation
+operator.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|'abc[' & i & ',' & j & ']'|
+
+\noindent\verb|"from " & city[i] & " to " & city[j]|
+
+\medskip
+
+The principles of evaluation of symbolic expressions are completely
+analogous to the ones given for numeric expressions (see above).
+
+\subsubsection{Function references}
+
+In MathProg there exist the following built-in functions which may be
+used in symbolic expressions:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt substr(}$s${\tt,} $x${\tt)}&substring of $s$ starting from
+position $x$\\
+{\tt substr(}$s${\tt,} $x${\tt,} $y${\tt)}&substring of $s$ starting
+from position $x$ and having length $y$\\
+{\tt time2str(}$t${\tt,} $f${\tt)}&converting calendar time to
+character string (for details see Subsection \ref{time2str}, page
+\pageref{time2str})\\
+\end{tabular}
+
+\medskip
+
+The first argument of {\tt substr} must be a symbolic expression while
+its second and optional third arguments must be numeric expressions.
+
+The first argument of {\tt time2str} must be a numeric expression, and
+its second argument must be a symbolic expression.
+
+The resultant value of the symbolic expression, which is a function
+reference, is the result of applying the function to its arguments.
+
+\subsubsection{Symbolic operators}
+
+Currently in MathProg there exists the only symbolic operator:
+
+\medskip
+
+\noindent\hfil
+{\tt s \& t}
+
+\medskip
+
+\noindent where $s$ and $t$ are symbolic expressions. This operator
+means concatenation of its two symbolic operands, which are character
+strings.
+
+\subsubsection{Hierarchy of operations}
+
+The following list shows the hierarchy of operations in symbolic
+expressions:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}ll@{}}
+Operation&Hierarchy\\
+\hline
+Evaluation of numeric operations&1st-7th\\
+Concatenation ({\tt\&})&8th\\
+Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
+7th\\
+\end{tabular}
+
+\medskip
+
+This hierarchy has the same meaning as was explained above for numeric
+expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
+
+\subsection{Indexing expressions and dummy indices}
+\label{indexing}
+
+An {\it indexing expression} is an auxiliary construction, which
+specifies a plain set of $n$-tuples and introduces dummy indices. It
+has two syntactic forms:
+
+\medskip
+
+\noindent\hspace{73.5pt}
+{\tt\{} {\it entry}$_1${\tt,} {\it entry}$_2${\tt,} \dots{\tt,}
+{\it entry}$_m$ {\tt\}}
+
+\medskip
+
+\noindent\hfil
+{\tt\{} {\it entry}$_1${\tt,} {\it entry}$_2${\tt,} \dots{\tt,}
+{\it entry}$_m$ {\tt:} {\it predicate} {\tt\}}
+
+\medskip
+
+\noindent where {\it entry}{$_1$}, {\it entry}{$_2$}, \dots,
+{\it entry}{$_m$} are indexing entries, {\it predicate} is a logical
+expression that specifies an optional predicate (logical condition).
+
+Each {\it indexing entry} in the indexing expression has one of the
+following three forms:
+
+\medskip
+
+\noindent\hspace{123pt}
+$i$ {\tt in} $S$
+
+\medskip
+
+\noindent\hfil
+{\tt(}$i_1${\tt,} $i_2${\tt,} \dots{\tt,}$i_n${\tt)} {\tt in} $S$
+
+\medskip
+
+\noindent\hspace{123pt}
+$S$
+
+\medskip
+
+\noindent where $i_1$, $i_2$, \dots, $i_n$ are indices, $S$ is a set
+expression (discussed in the next section) that specifies the basic set.
+
+The number of indices in the indexing entry must be the same as the
+dimension of the basic set $S$, i.e. if $S$ consists of 1-tuples, the
+first form must be used, and if $S$ consists of $n$-tuples, where
+$n>1$, the second form must be used.
+
+If the first form of the indexing entry is used, the index $i$ can be
+a dummy index only (see below). If the second form is used, the indices
+$i_1$, $i_2$, \dots, $i_n$ can be either dummy indices or some numeric
+or symbolic expressions, where at least one index must be a dummy index.
+The third, reduced form of the indexing entry has the same effect as if
+there were $i$ (if $S$ is 1-dimensional) or $i_1$, $i_2$, \dots, $i_n$
+(if $S$ is $n$-dimensional) all specified as dummy indices.
+
+A {\it dummy index} is an auxiliary model object, which acts like an
+individual variable. Values assigned to dummy indices are components of
+$n$-tuples from basic sets, i.e. some numeric and symbolic quantities.
+
+For referencing purposes dummy indices can be provided with symbolic
+names. However, unlike other model objects (sets, parameters, etc.)
+dummy indices need not be explicitly declared. Each {\it undeclared}
+symbolic name being used in the indexing position of an indexing entry
+is recognized as the symbolic name of corresponding dummy index.
+
+Symbolic names of dummy indices are valid only within the scope of the
+indexing expression, where the dummy indices were introduced. Beyond
+the scope the dummy indices are completely inaccessible, so the same
+symbolic names may be used for other purposes, in particular, to
+represent dummy indices in other indexing expressions.
+
+The scope of indexing expression, where implicit declarations of dummy
+indices are valid, depends on the context, in which the indexing
+expression is used:
+
+\begin{enumerate}
+\item If the indexing expression is used in iterated operator, its
+scope extends until the end of the integrand.
+\item If the indexing expression is used as a primary set expression,
+its scope extends until the end of that indexing expression.
+\item If the indexing expression is used to define the subscript domain
+in declarations of some model objects, its scope extends until the end
+of the corresponding statement.
+\end{enumerate}
+
+The indexing mechanism implemented by means of indexing expressions is
+best explained by some examples discussed below.
+
+Let there be given three sets:
+
+\medskip
+
+\noindent\hspace{33.5pt}
+$A=\{4,7,9\}$,
+
+\medskip
+
+\noindent\hfil
+$B=\{(1,Jan),(1,Feb),(2,Mar),(2,Apr),(3,May),(3,Jun)\}$,
+
+\medskip
+
+\noindent\hspace{33.5pt}
+$C=\{a,b,c\}$,
+
+\medskip
+
+\noindent where $A$ and $C$ consist of 1-tuples (singlets), $B$
+consists of 2-tuples (doublets). Consider the following indexing
+expression:
+
+\medskip
+
+\noindent\hfil
+{\tt\{i in A, (j,k) in B, l in C\}}
+
+\medskip
+
+\noindent where {\tt i}, {\tt j}, {\tt k}, and {\tt l} are dummy
+indices.
+
+Although MathProg is not a procedural language, for any indexing
+expression an equivalent algorithmic description can be given. In
+particular, the algorithmic description of the indexing expression
+above could look like follows:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}l@{}}
+{\bf for all} $i\in A$ {\bf do}\\
+\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf do}\\
+\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
+\hspace{36pt}{\it action};\\
+\end{tabular}
+
+\newpage
+
+\noindent where the dummy indices $i$, $j$, $k$, $l$ are consecutively
+assigned corresponding components of $n$-tuples from the basic sets $A$,
+$B$, $C$, and {\it action} is some action that depends on the context,
+where the indexing expression is used. For example, if the action were
+printing current values of dummy indices, the printout would look like
+follows:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}llll@{}}
+$i=4$&$j=1$&$k=Jan$&$l=a$\\
+$i=4$&$j=1$&$k=Jan$&$l=b$\\
+$i=4$&$j=1$&$k=Jan$&$l=c$\\
+$i=4$&$j=1$&$k=Feb$&$l=a$\\
+$i=4$&$j=1$&$k=Feb$&$l=b$\\
+\multicolumn{4}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
+$i=9$&$j=3$&$k=Jun$&$l=b$\\
+$i=9$&$j=3$&$k=Jun$&$l=c$\\
+\end{tabular}
+
+\medskip
+
+Let the example indexing expression be used in the following iterated
+operation:
+
+\medskip
+
+\noindent\hfil
+{\tt sum\{i in A, (j,k) in B, l in C\} p[i,j,k,l]}
+
+\medskip
+
+\noindent where {\tt p} is a 4-dimensional numeric parameter or some
+numeric expression whose resultant value depends on {\tt i}, {\tt j},
+{\tt k}, and {\tt l}. In this case the action is summation, so the
+resultant value of the primary numeric expression is:
+$$\sum_{i\in A,(j,k)\in B,l\in C}(p_{ijkl}).$$
+
+Now let the example indexing expression be used as a primary set
+expression. In this case the action is gathering all 4-tuples
+(quadruplets) of the form $(i,j,k,l)$ in one set, so the resultant
+value of such operation is simply the Cartesian product of the basic
+sets:
+$$A\times B\times C=\{(i,j,k,l):i\in A,(j,k)\in B,l\in C\}.$$
+Note that in this case the same indexing expression might be written in
+the reduced form:
+
+\medskip
+
+\noindent\hfil
+{\tt\{A, B, C\}}
+
+\medskip
+
+\noindent because the dummy indices $i$, $j$, $k$, and $l$ are not
+referenced and therefore their symbolic names need not be specified.
+
+Finally, let the example indexing expression be used as the subscript
+domain in the declaration of a 4-dimensional model object, say,
+a numeric parameter:
+
+\medskip
+
+\noindent\hfil
+{\tt param p\{i in A, (j,k) in B, l in C\}} \dots {\tt;}
+
+\medskip
+
+\noindent In this case the action is generating the parameter members,
+where each member has the form $p[i,j,k,l]$.
+
+As was said above, some indices in the second form of indexing entries
+may be numeric or symbolic expressions, not only dummy indices. In this
+case resultant values of such expressions play role of some logical
+conditions to select only that $n$-tuples from the Cartesian product of
+basic sets that satisfy these conditions.
+
+Consider, for example, the following indexing expression:
+
+\medskip
+
+\noindent\hfil
+{\tt\{i in A, (i-1,k) in B, l in C\}}
+
+\medskip
+
+\noindent where {\tt i}, {\tt k}, {\tt l} are dummy indices, and
+{\tt i-1} is a numeric expression. The algorithmic decsription of this
+indexing expression is the following:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}l@{}}
+{\bf for all} $i\in A$ {\bf do}\\
+\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf and} $j=i-1$ {\bf do}\\
+\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
+\hspace{36pt}{\it action};\\
+\end{tabular}
+
+\medskip
+
+\noindent Thus, if this indexing expression were used as a primary set
+expression, the resultant set would be the following:
+$$\{(4,May,a),(4,May,b),(4,May,c),(4,Jun,a),(4,Jun,b),(4,Jun,c)\}.$$
+Should note that in this case the resultant set consists of 3-tuples,
+not of 4-tuples, because in the indexing expression there is no dummy
+index that corresponds to the first component of 2-tuples from the set
+$B$.
+
+The general rule is: the number of components of $n$-tuples defined by
+an indexing expression is the same as the number of dummy indices in
+that expression, where the correspondence between dummy indices and
+components on $n$-tuples in the resultant set is positional, i.e. the
+first dummy index corresponds to the first component, the second dummy
+index corresponds to the second component, etc.
+
+In some cases it is needed to select a subset from the Cartesian
+product of some sets. This may be attained by using an optional logical
+predicate, which is specified in the indexing expression.
+
+Consider, for example, the following indexing expression:
+
+\medskip
+
+\noindent\hfil
+{\tt\{i in A, (j,k) in B, l in C: i <= 5 and k <> 'Mar'\}}
+
+\medskip
+
+\noindent where the logical expression following the colon is a
+predicate. The algorithmic description of this indexing expression is
+the following:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}l@{}}
+{\bf for all} $i\in A$ {\bf do}\\
+\hspace{12pt}{\bf for all} $(j,k)\in B$ {\bf do}\\
+\hspace{24pt}{\bf for all} $l\in C$ {\bf do}\\
+\hspace{36pt}{\bf if} $i\leq 5$ {\bf and} $l\neq`Mar'$ {\bf then}\\
+\hspace{48pt}{\it action};\\
+\end{tabular}
+
+\medskip
+
+\noindent Thus, if this indexing expression were used as a primary set
+expression, the resultant set would be the following:
+$$\{(4,1,Jan,a),(4,1,Feb,a),(4,2,Apr,a),\dots,(4,3,Jun,c)\}.$$
+
+If no predicate is specified in the indexing expression, one, which
+takes on the value {\it true}, is assumed.
+
+\subsection{Set expressions}
+
+A {\it set expression} is a rule for computing an elemental set, i.e.
+a collection of $n$-tuples, where components of $n$-tuples are numeric
+and symbolic quantities.
+
+The primary set expression may be a literal set, unsubscripted set,
+subscripted set, ``arithmetic'' set, indexing expression, iterated set
+expression, conditional set expression, or another set expression
+enclosed in parentheses.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent
+\begin{tabular}{@{}ll@{}}
+\verb|{(123,'aa'), (i,'bb'), (j-1,'cc')}|&(literal set)\\
+\verb|I|&(unsubscripted set)\\
+\verb|S[i-1,j+1]|&(subscripted set)\\
+\verb|1..t-1 by 2|&(``arithmetic'' set)\\
+\verb|{t in 1..T, (t+1,j) in S: (t,j) in F}|&(indexing expression)\\
+\verb|setof{i in I, j in J}(i+1,j-1)|&(iterated expression)\\
+\verb|if i < j then S[i] else F diff S[j]|&(conditional expression)\\
+\verb|(1..10 union 21..30)|&(parenthesized expression)\\
+\end{tabular}
+
+\medskip
+
+More general set expressions containing two or more primary set
+expressions may be constructed by using certain set operators.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|(A union B) inter (I cross J)|
+
+\noindent
+\verb|1..10 cross (if i < j then {'a', 'b', 'c'} else {'d', 'e', 'f'})|
+
+\subsubsection{Literal sets}
+
+A {\it literal set} is a primary set expression, which has the
+following two syntactic forms:
+
+\medskip
+
+\noindent\hspace{39pt}
+{\tt\{}$e_1${\tt,} $e_2${\tt,} \dots{\tt,} $e_m${\tt\}}
+
+\medskip
+
+\noindent\hfil
+{\tt\{(}$e_{11}${\tt,} \dots{\tt,} $e_{1n}${\tt),}
+{\tt(}$e_{21}${\tt,} \dots{\tt,} $e_{2n}${\tt),} \dots{\tt,}
+{\tt(}$e_{m1}${\tt,} \dots{\tt,} $e_{mn}${\tt)\}}
+
+\medskip
+
+\noindent where $e_1$, \dots, $e_m$, $e_{11}$, \dots, $e_{mn}$ are
+numeric or symbolic expressions.
+
+If the first form is used, the resultant set consists of 1-tuples
+(singlets) enumerated within the curly braces. It is allowed to specify
+an empty set as {\tt\{\ \}}, which has no 1-tuples. If the second form
+is used, the resultant set consists of $n$-tuples enumerated within the
+curly braces, where a particular $n$-tuple consists of corresponding
+components enumerated within the parentheses. All $n$-tuples must have
+the same number of components.
+
+\subsubsection{Unsubscripted sets}
+
+If the primary set expression is an unsubscripted set (which must be
+0-dimen\-sional), the resultant set is an elemental set associated with
+the corresponding set object.
+
+\newpage
+
+\subsubsection{Subscripted sets}
+
+The primary set expression, which refers to a subscripted set, has the
+following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
+
+\medskip
+
+\noindent where {\it name} is the symbolic name of the set object,
+$i_1$, $i_2$, \dots, $i_n$ are subscripts.
+
+Each subscript must be a numeric or symbolic expression. The number of
+subscripts in the subscript list must be the same as the dimension of
+the set object with which the subscript list is associated.
+
+Actual values of subscript expressions are used to identify a
+particular member of the set object that determines the resultant set.
+
+\subsubsection{``Arithmetic'' sets}
+
+The primary set expression, which is an ``arithmetic'' set, has the
+following two syntactic forms:
+
+\medskip
+
+\noindent\hfil
+$t_0$ {\tt..} $t_1$ {\tt by} $\delta t$
+
+\medskip
+
+\noindent\hspace{138.5pt}
+$t_0$ {\tt..} $t_1$
+
+\medskip
+
+\noindent where $t_0$, $t_1$, and $\delta t$ are numeric expressions
+(the value of $\delta t$ must not be zero). The second form is
+equivalent to the first form, where $\delta t=1$.
+
+If $\delta t>0$, the resultant set is determined as follows:
+$$\{t:\exists k\in{\cal Z}(t=t_0+k\delta t,\ t_0\leq t\leq t_1)\}.$$
+Otherwise, if $\delta t<0$, the resultant set is determined as follows:
+$$\{t:\exists k\in{\cal Z}(t=t_0+k\delta t,\ t_1\leq t\leq t_0)\}.$$
+
+\subsubsection{Indexing expressions}
+
+If the primary set expression is an indexing expression, the resultant
+set is determined as described above in Subsection \ref{indexing}, page
+\pageref{indexing}.
+
+\subsubsection{Iterated expressions}
+
+An {\it iterated set expression} is a primary set expression, which has
+the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\tt setof} {\it indexing-expression} {\it integrand}
+
+\medskip
+
+\noindent where {\it indexing-expression} is an indexing expression,
+which introduces dummy indices and controls iterating, {\it integrand}
+is either a single numeric or symbolic expression or a list of numeric
+and symbolic expressions separated by commae and enclosed in
+parentheses.
+
+If the integrand is a single numeric or symbolic expression, the
+resultant set consists of 1-tuples and is determined as follows:
+$$\{x:(i_1,\dots,i_n)\in\Delta\},$$
+\noindent where $x$ is a value of the integrand, $i_1$, \dots, $i_n$
+are dummy indices introduced in the indexing expression, $\Delta$ is
+the domain, a set of $n$-tuples specified by the indexing expression,
+which defines particular values assigned to the dummy indices on
+performing the iterated operation.
+
+If the integrand is a list containing $m$ numeric and symbolic
+expressions, the resultant set consists of $m$-tuples and is determined
+as follows:
+$$\{(x_1,\dots,x_m):(i_1,\dots,i_n)\in\Delta\},$$
+where $x_1$, \dots, $x_m$ are values of the expressions in the
+integrand list, $i_1$, \dots, $i_n$ and $\Delta$ have the same meaning
+as above.
+
+\subsubsection{Conditional expressions}
+
+A {\it conditional set expression} is a primary set expression that has
+the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\tt if} $b$ {\tt then} $X$ {\tt else} $Y$
+
+\medskip
+
+\noindent where $b$ is an logical expression, $X$ and $Y$ are set
+expressions, which must define sets of the same dimension.
+
+The resultant value of the conditional expression depends on the value
+of the logical expression that follows the keyword {\tt if}. If it
+takes on the value {\it true}, the resultant set is the value of the
+expression that follows the keyword {\tt then}. Otherwise, if the
+logical expression takes on the value {\it false}, the resultant set is
+the value of the expression that follows the keyword {\tt else}.
+
+\subsubsection{Parenthesized expressions}
+
+Any set expression may be enclosed in parentheses that syntactically
+makes it a primary set expression.
+
+Parentheses may be used in set expressions, as in algebra, to specify
+the desired order in which operations are to be performed. Where
+parentheses are used, the expression within the parentheses is
+evaluated before the resultant value is used.
+
+The resultant value of the parenthesized expression is the same as the
+value of the expression enclosed within parentheses.
+
+\subsubsection{Set operators}
+
+In MathProg there exist the following set operators, which may be used
+in set expressions:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+$X$ {\tt union} $Y$&union $X\cup Y$\\
+$X$ {\tt diff} $Y$&difference $X\backslash Y$\\
+$X$ {\tt symdiff} $Y$&symmetric difference $X\oplus Y$\\
+$X$ {\tt inter} $Y$&intersection $X\cap Y$\\
+$X$ {\tt cross} $Y$&cross (Cartesian) product $X\times Y$\\
+\end{tabular}
+
+\medskip
+
+\noindent where $X$ and Y are set expressions, which must define sets
+of the identical dimension (except the Cartesian product).
+
+If the expression includes more than one set operator, all operators
+are performed from left to right according to the hierarchy of
+operations (see below).
+
+The resultant value of the expression, which contains set operators, is
+the result of applying the operators to their operands.
+
+The dimension of the resultant set, i.e. the dimension of $n$-tuples,
+of which the resultant set consists of, is the same as the dimension of
+the operands, except the Cartesian product, where the dimension of the
+resultant set is the sum of the dimensions of its operands.
+
+\subsubsection{Hierarchy of operations}
+
+The following list shows the hierarchy of operations in set
+expressions:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}ll@{}}
+Operation&Hierarchy\\
+\hline
+Evaluation of numeric operations&1st-7th\\
+Evaluation of symbolic operations&8th-9th\\
+Evaluation of iterated or ``arithmetic'' set ({\tt setof}, {\tt..})&
+10th\\
+Cartesian product ({\tt cross})&11th\\
+Intersection ({\tt inter})&12th\\
+Union and difference ({\tt union}, {\tt diff}, {\tt symdiff})&13th\\
+Conditional evaluation ({\tt if} \dots {\tt then} \dots {\tt else})&
+14th\\
+\end{tabular}
+
+\medskip
+
+This hierarchy has the same meaning as was explained above for numeric
+expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
+
+\subsection{Logical expressions}
+
+A {\it logical expression} is a rule for computing a single logical
+value, which can be either {\it true} or {\it false}.
+
+The primary logical expression may be a numeric expression, relational
+expression, iterated logical expression, or another logical expression
+enclosed in parentheses.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent
+\begin{tabular}{@{}ll@{}}
+\verb|i+1|&(numeric expression)\\
+\verb|a[i,j] < 1.5|&(relational expression)\\
+\verb|s[i+1,j-1] <> 'Mar'|&(relational expression)\\
+\verb|(i+1,'Jan') not in I cross J|&(relational expression)\\
+\verb|S union T within A[i] inter B[j]|&(relational expression)\\
+\verb|forall{i in I, j in J} a[i,j] < .5 * b|&(iterated expression)\\
+\verb|(a[i,j] < 1.5 or b[i] >= a[i,j])|&(parenthesized expression)\\
+\end{tabular}
+
+\medskip
+
+More general logical expressions containing two or more primary logical
+expressions may be constructed by using certain logical operators.
+
+\newpage
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|not (a[i,j] < 1.5 or b[i] >= a[i,j]) and (i,j) in S|
+
+\noindent\verb|(i,j) in S or (i,j) not in T diff U|
+
+\subsubsection{Numeric expressions}
+
+The resultant value of the primary logical expression, which is a
+numeric expression, is {\it true}, if the resultant value of the
+numeric expression is non-zero. Otherwise the resultant value of the
+logical expression is {\it false}.
+
+\subsubsection{Relational operators}
+
+In MathProg there exist the following relational operators, which may
+be used in logical expressions:
+
+\medskip
+
+\begin{tabular}{@{}ll@{}}
+$x$ {\tt<} $y$&test on $x<y$\\
+$x$ {\tt<=} $y$&test on $x\leq y$\\
+$x$ {\tt=} $y$, $x$ {\tt==} $y$&test on $x=y$\\
+$x$ {\tt>=} $y$&test on $x\geq y$\\
+$x$ {\tt>} $y$&test on $x>y$\\
+$x$ {\tt<>} $y$, $x$ {\tt!=} $y$&test on $x\neq y$\\
+$x$ {\tt in} $Y$&test on $x\in Y$\\
+{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt in} $Y$&test on
+$(x_1,\dots,x_n)\in Y$\\
+$x$ {\tt not} {\tt in} $Y$, $x$ {\tt!in} $Y$&test on $x\not\in Y$\\
+{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt not} {\tt in} $Y$,
+{\tt(}$x_1${\tt,}\dots{\tt,}$x_n${\tt)} {\tt !in} $Y$&test on
+$(x_1,\dots,x_n)\not\in Y$\\
+$X$ {\tt within} $Y$&test on $X\subseteq Y$\\
+$X$ {\tt not} {\tt within} $Y$, $X$ {\tt !within} $Y$&test on
+$X\not\subseteq Y$\\
+\end{tabular}
+
+\medskip
+
+\noindent where $x$, $x_1$, \dots, $x_n$, $y$ are numeric or symbolic
+expressions, $X$ and $Y$ are set expression.
+
+{\it Notes:}
+
+1. In the operations {\tt in}, {\tt not in}, and {\tt !in} the
+number of components in the first operands must be the same as the
+dimension of the second operand.
+
+2. In the operations {\tt within}, {\tt not within}, and {\tt !within}
+both operands must have identical dimension.
+
+All the relational operators listed above have their conventional
+mathematical meaning. The resultant value is {\it true}, if
+corresponding relation is satisfied for its operands, otherwise
+{\it false}. (Note that symbolic values are ordered lexicographically,
+and any numeric value precedes any symbolic value.)
+
+\subsubsection{Iterated expressions}
+
+An {\it iterated logical expression} is a primary logical expression,
+which has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\it iterated-operator} {\it indexing-expression} {\it integrand}
+
+\medskip
+
+\noindent where {\it iterated-operator} is the symbolic name of the
+iterated operator to be performed (see below), {\it indexing-expression}
+is an indexing expression which introduces dummy indices and controls
+iterating, {\it integrand} is a numeric expression that participates in
+the operation.
+
+In MathProg there exist two iterated operators, which may be used in
+logical expressions:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}lll@{}}
+{\tt forall}&$\forall$-quantification&$\displaystyle
+\forall(i_1,\dots,i_n)\in\Delta[f(i_1,\dots,i_n)],$\\
+{\tt exists}&$\exists$-quantification&$\displaystyle
+\exists(i_1,\dots,i_n)\in\Delta[f(i_1,\dots,i_n)],$\\
+\end{tabular}
+
+\medskip
+
+\noindent where $i_1$, \dots, $i_n$ are dummy indices introduced in
+the indexing expression, $\Delta$ is the domain, a set of $n$-tuples
+specified by the indexing expression which defines particular values
+assigned to the dummy indices on performing the iterated operation,
+$f(i_1,\dots,i_n)$ is the integrand, a logical expression whose
+resultant value depends on the dummy indices.
+
+For $\forall$-quantification the resultant value of the iterated
+logical expression is {\it true}, if the value of the integrand is
+{\it true} for all $n$-tuples contained in the domain, otherwise
+{\it false}.
+
+For $\exists$-quantification the resultant value of the iterated
+logical expression is {\it false}, if the value of the integrand is
+{\it false} for all $n$-tuples contained in the domain, otherwise
+{\it true}.
+
+\subsubsection{Parenthesized expressions}
+
+Any logical expression may be enclosed in parentheses that
+syntactically makes it a primary logical expression.
+
+Parentheses may be used in logical expressions, as in algebra, to
+specify the desired order in which operations are to be performed.
+Where parentheses are used, the expression within the parentheses is
+evaluated before the resultant value is used.
+
+The resultant value of the parenthesized expression is the same as the
+value of the expression enclosed within parentheses.
+
+\subsubsection{Logical operators}
+
+In MathProg there exist the following logical operators, which may be
+used in logical expressions:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt not} $x$, {\tt!}$x$&negation $\neg\ x$\\
+$x$ {\tt and} $y$, $x$ {\tt\&\&} $y$&conjunction (logical ``and'')
+$x\;\&\;y$\\
+$x$ {\tt or} $y$, $x$ {\tt||} $y$&disjunction (logical ``or'')
+$x\vee y$\\
+\end{tabular}
+
+\medskip
+
+\noindent where $x$ and $y$ are logical expressions.
+
+If the expression includes more than one logical operator, all
+operators are performed from left to right according to the hierarchy
+of the operations (see below). The resultant value of the expression,
+which contains logical operators, is the result of applying the
+operators to their operands.
+
+\subsubsection{Hierarchy of operations}
+
+The following list shows the hierarchy of operations in logical
+expressions:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}ll@{}}
+Operation&Hierarchy\\
+\hline
+Evaluation of numeric operations&1st-7th\\
+Evaluation of symbolic operations&8th-9th\\
+Evaluation of set operations&10th-14th\\
+Relational operations ({\tt<}, {\tt<=}, etc.)&15th\\
+Negation ({\tt not}, {\tt!})&16th\\
+Conjunction ({\tt and}, {\tt\&\&})&17th\\
+$\forall$- and $\exists$-quantification ({\tt forall}, {\tt exists})&
+18th\\
+Disjunction ({\tt or}, {\tt||})&19th\\
+\end{tabular}
+
+\medskip
+
+This hierarchy has the same meaning as was explained above for numeric
+expressions (see Subsection \ref{hierarchy}, page \pageref{hierarchy}).
+
+\subsection{Linear expressions}
+
+An {\it linear expression} is a rule for computing so called
+a {\it linear form} or simply a {\it formula}, which is a linear (or
+affine) function of elemental variables.
+
+The primary linear expression may be an unsubscripted variable,
+subscripted variable, iterated linear expression, conditional linear
+expression, or another linear expression enclosed in parentheses.
+
+It is also allowed to use a numeric expression as the primary linear
+expression, in which case the resultant value of the numeric expression
+is automatically converted to a formula that includes the constant term
+only.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent
+\begin{tabular}{@{}ll@{}}
+\verb|z|&(unsubscripted variable)\\
+\verb|x[i,j]|&(subscripted variable)\\
+\verb|sum{j in J} (a[i] * x[i,j] + 3 * y)|&(iterated expression)\\
+\verb|if i in I then x[i,j] else 1.5 * z + 3|&(conditional expression)\\
+\verb|(a[i,j] * x[i,j] + y[i-1] + .1)|&(parenthesized expression)\\
+\end{tabular}
+
+\medskip
+
+More general linear expressions containing two or more primary linear
+expressions may be constructed by using certain arithmetic operators.
+
+\medskip
+
+\noindent{\bf Examples}
+
+\medskip
+
+\noindent\verb|2 * x[i-1,j+1] + 3.5 * y[k] + .5 * z|
+
+\noindent\verb|(- x[i,j] + 3.5 * y[k]) / sum{t in T} abs(d[i,j,t])|
+
+\subsubsection{Unsubscripted variables}
+
+If the primary linear expression is an unsubscripted variable (which
+must be 0-dimensional), the resultant formula is that unsubscripted
+variable.
+
+\subsubsection{Subscripted variables}
+
+The primary linear expression, which refers to a subscripted variable,
+has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\it name}{\tt[}$i_1${\tt,} $i_2${\tt,} \dots{\tt,} $i_n${\tt]}
+
+\medskip
+
+\noindent where {\it name} is the symbolic name of the model variable,
+$i_1$, $i_2$, \dots, $i_n$ are subscripts.
+
+Each subscript must be a numeric or symbolic expression. The number of
+subscripts in the subscript list must be the same as the dimension of
+the model variable with which the subscript list is associated.
+
+Actual values of the subscript expressions are used to identify a
+particular member of the model variable that determines the resultant
+formula, which is an elemental variable associated with corresponding
+member.
+
+\subsubsection{Iterated expressions}
+
+An {\it iterated linear expression} is a primary linear expression,
+which has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\tt sum} {\it indexing-expression} {\it integrand}
+
+\medskip
+
+\noindent where {\it indexing-expression} is an indexing expression,
+which introduces dummy indices and controls iterating, {\it integrand}
+is a linear expression that participates in the operation.
+
+The iterated linear expression is evaluated exactly in the same way as
+the iterated numeric expression (see Subection \ref{itexpr}, page
+\pageref{itexpr}) with exception that the integrand participated in the
+summation is a formula, not a numeric value.
+
+\subsubsection{Conditional expressions}
+
+A {\it conditional linear expression} is a primary linear expression,
+which has one of the following two syntactic forms:
+
+\medskip
+
+\noindent\hfil
+{\tt if} $b$ {\tt then} $f$ {\tt else} $g$
+
+\medskip
+
+\noindent\hspace{127pt}
+{\tt if} $b$ {\tt then} $f$
+
+\medskip
+
+\noindent where $b$ is an logical expression, $f$ and $g$ are linear
+expressions.
+
+The conditional linear expression is evaluated exactly in the same way
+as the conditional numeric expression (see Subsection \ref{ifthen},
+page \pageref{ifthen}) with exception that operands participated in the
+operation are formulae, not numeric values.
+
+\subsubsection{Parenthesized expressions}
+
+Any linear expression may be enclosed in parentheses that syntactically
+makes it a primary linear expression.
+
+Parentheses may be used in linear expressions, as in algebra, to
+specify the desired order in which operations are to be performed.
+Where parentheses are used, the expression within the parentheses is
+evaluated before the resultant formula is used.
+
+The resultant value of the parenthesized expression is the same as the
+value of the expression enclosed within parentheses.
+
+\subsubsection{Arithmetic operators}
+
+In MathProg there exists the following arithmetic operators, which may
+be used in linear expressions:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt+} $f$&unary plus\\
+{\tt-} $f$&unary minus\\
+$f$ {\tt+} $g$&addition\\
+$f$ {\tt-} $g$&subtraction\\
+$x$ {\tt*} $f$, $f$ {\tt*} $x$&multiplication\\
+$f$ {\tt/} $x$&division
+\end{tabular}
+
+\medskip
+
+\noindent where $f$ and $g$ are linear expressions, $x$ is a numeric
+expression (more precisely, a linear expression containing only the
+constant term).
+
+If the expression includes more than one arithmetic operator, all
+operators are performed from left to right according to the hierarchy
+of operations (see below). The resultant value of the expression, which
+contains arithmetic operators, is the result of applying the operators
+to their operands.
+
+\subsubsection{Hierarchy of operations}
+
+The hierarchy of arithmetic operations used in linear expressions is
+the same as for numeric expressions (see Subsection \ref{hierarchy},
+page \pageref{hierarchy}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Statements}
+
+{\it Statements} are basic units of the model description. In MathProg
+all statements are divided into two categories: declaration statements
+and functional statements.
+
+{\it Declaration statements} (set statement, parameter statement,
+variable statement, constraint statement, and objective statement) are
+used to declare model objects of certain kinds and define certain
+properties of such objects.
+
+{\it Functional statements} (solve statement, check statement, display
+statement, printf statement, loop statement) are intended for
+performing some specific actions.
+
+Note that declaration statements may follow in arbitrary order, which
+does not affect the result of translation. However, any model object
+must be declared before it is referenced in other statements.
+
+\subsection{Set statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][24pt]{345pt}{
+\hspace{6pt} {\tt set} {\it name} {\it alias} {\it domain} {\tt,}
+{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+set;
+\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
+specifies an alias of the set;
+\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
+which specifies a subscript domain of the set;
+\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
+attributes of the set. (Commae preceding attributes may be omitted.)
+\end{description}
+
+\noindent Optional attributes:
+
+\begin{description}
+\item[{\tt dimen} $n$\hspace*{19pt}] specifies the dimension of
+$n$-tuples, which the set consists of;
+\item[{\tt within} {\it expression}]\hspace*{0pt}\\
+specifies a superset which restricts the set or all its members
+(elemental sets) to be within that superset;
+\item[{\tt:=} {\it expression}]\hspace*{0pt}\\
+specifies an elemental set assigned to the set or its members;
+\item[{\tt default} {\it expression}]\hspace*{0pt}\\
+specifies an elemental set assigned to the set or its members whenever
+no appropriate data are available in the data section.
+\end{description}
+
+\newpage
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+set V;
+set E within V cross V;
+set step{s in 1..maxiter} dimen 2 := if s = 1 then E else
+   step[s-1] union setof{k in V, (i,k) in step[s-1], (k,j)
+   in step[s-1]}(i,j);
+set A{i in I, j in J}, within B[i+1] cross C[j-1], within
+   D diff E, default {('abc',123), (321,'cba')};
+\end{verbatim}
+
+The set statement declares a set. If the subscript domain is not
+specified, the set is a simple set, otherwise it is an array of
+elemental sets.
+
+The {\tt dimen} attribute specifies the dimension of $n$-tuples, which
+the set (if it is a simple set) or its members (if the set is an array
+of elemental sets) consist of, where $n$ must be unsigned integer from
+1 to 20. At most one {\tt dimen} attribute can be specified. If the
+{\tt dimen} attribute is not specified, the dimension of\linebreak
+$n$-tuples is implicitly determined by other attributes (for example,
+if there is a set expression that follows {\tt:=} or the keyword
+{\tt default}, the dimension of $n$-tuples of corresponding elemental
+set is used). If no dimension information is available, {\tt dimen 1}
+is assumed.
+
+The {\tt within} attribute specifies a set expression whose resultant
+value is a superset used to restrict the set (if it is a simple set) or
+its members (if the set is an array of elemental sets) to be within
+that superset. Arbitrary number of {\tt within} attributes may be
+specified in the same set statement.
+
+The assign ({\tt:=}) attribute specifies a set expression used to
+evaluate elemental set(s) assigned to the set (if it is a simple set)
+or its members (if the set is an array of elemental sets). If the
+assign attribute is specified, the set is {\it computable} and
+therefore needs no data to be provided in the data section. If the
+assign attribute is not specified, the set must be provided with data
+in the data section. At most one assign or default attribute can be
+specified for the same set.
+
+The {\tt default} attribute specifies a set expression used to evaluate
+elemental set(s) assigned to the set (if it is a simple set) or its
+members (if the set is an array of elemental sets) whenever
+no appropriate data are available in the data section. If neither
+assign nor default attribute is specified, missing data will cause an
+error.
+
+\subsection{Parameter statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][24pt]{345pt}{
+\hspace{6pt} {\tt param} {\it name} {\it alias} {\it domain} {\tt,}
+{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+parameter;
+\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
+specifies an alias of the parameter;
+\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
+which specifies a subscript domain of the parameter;
+\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
+attributes of the parameter. (Commae preceding attributes may be
+omitted.)
+\end{description}
+
+\noindent Optional attributes:
+
+\begin{description}
+\item[{\tt integer}\hspace*{18.5pt}] specifies that the parameter is
+integer;
+\item[{\tt binary}\hspace*{24pt}] specifies that the parameter is
+binary;
+\item[{\tt symbolic}\hspace*{13.5pt}] specifies that the parameter is
+symbolic;
+\item[{\it relation expression}]\hspace*{0pt}\\
+(where {\it relation} is one of: {\tt<}, {\tt<=}, {\tt=}, {\tt==},
+{\tt>=}, {\tt>}, {\tt<>}, {\tt!=})\\
+specifies a condition that restricts the parameter or its members to
+satisfy that condition;
+\item[{\tt in} {\it expression}]\hspace*{0pt}\\
+specifies a superset that restricts the parameter or its members to be
+in that superset;
+\item[{\tt:=} {\it expression}]\hspace*{0pt}\\
+specifies a value assigned to the parameter or its members;
+\item[{\tt default} {\it expression}]\hspace*{0pt}\\
+specifies a value assigned to the parameter or its members whenever
+no appropriate data are available in the data section.
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+param units{raw, prd} >= 0;
+param profit{prd, 1..T+1};
+param N := 20, integer, >= 0, <= 100;
+param comb 'n choose k' {n in 0..N, k in 0..n} :=
+   if k = 0 or k = n then 1 else comb[n-1,k-1] + comb[n-1,k];
+param p{i in I, j in J}, integer, >= 0, <= i+j,
+   in A[i] symdiff B[j], in C[i,j], default 0.5 * (i + j);
+param month symbolic default 'May' in {'Mar', 'Apr', 'May'};
+\end{verbatim}
+
+The parameter statement declares a parameter. If a subscript domain is
+not specified, the parameter is a simple (scalar) parameter, otherwise
+it is a $n$-dimensional array.
+
+The type attributes {\tt integer}, {\tt binary}, and {\tt symbolic}
+qualify the type of values that can be assigned to the parameter as
+shown below:
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{@{}ll@{}}
+Type attribute&Assigned values\\
+\hline
+(not specified)&Any numeric values\\
+{\tt integer}&Only integer numeric values\\
+{\tt binary}&Either 0 or 1\\
+{\tt symbolic}&Any numeric and symbolic values\\
+\end{tabular}
+
+\newpage
+
+The {\tt symbolic} attribute cannot be specified along with other type
+attributes. Being specified it must precede all other attributes.
+
+The condition attribute specifies an optional condition that restricts
+values assigned to the parameter to satisfy that condition. This
+attribute has the following syntactic forms:
+
+\medskip
+
+\begin{tabular}{@{}ll@{}}
+{\tt<} $v$&check for $x<v$\\
+{\tt<=} $v$&check for $x\leq v$\\
+{\tt=} $v$, {\tt==} $v$&check for $x=v$\\
+{\tt>=} $v$&check for $x\geq v$\\
+{\tt>} $v$&check for $x\geq v$\\
+{\tt<>} $v$, {\tt!=} $v$&check for $x\neq v$\\
+\end{tabular}
+
+\medskip
+
+\noindent where $x$ is a value assigned to the parameter, $v$ is the
+resultant value of a numeric or symbolic expression specified in the
+condition attribute. Arbitrary number of condition attributes can be
+specified for the same parameter. If a value being assigned to the
+parameter during model evaluation violates at least one of specified
+conditions, an error is raised. (Note that symbolic values are ordered
+lexicographically, and any numeric value precedes any symbolic value.)
+
+The {\tt in} attribute is similar to the condition attribute and
+specifies a set expression whose resultant value is a superset used to
+restrict numeric or symbolic values assigned to the parameter to be in
+that superset. Arbitrary number of the {\tt in} attributes can be
+specified for the same parameter. If a value being assigned to the
+parameter during model evaluation is not in at least one of specified
+supersets, an error is raised.
+
+The assign ({\tt:=}) attribute specifies a numeric or symbolic
+expression used to compute a value assigned to the parameter (if it is
+a simple parameter) or its member (if the parameter is an array). If
+the assign attribute is specified, the parameter is {\it computable}
+and therefore needs no data to be provided in the data section. If the
+assign attribute is not specified, the parameter must be provided with
+data in the data section. At most one assign or {\tt default} attribute
+can be specified for the same parameter.
+
+The {\tt default} attribute specifies a numeric or symbolic expression
+used to compute a value assigned to the parameter or its member
+whenever no appropriate data are available in the data section. If
+neither assign nor {\tt default} attribute is specified, missing data
+will cause an error.
+
+\subsection{Variable statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][24pt]{345pt}{
+\hspace{6pt} {\tt var} {\it name} {\it alias} {\it domain} {\tt,}
+{\it attrib} {\tt,} \dots {\tt,} {\it attrib} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+variable;
+\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
+specifies an alias of the variable;
+\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
+which specifies a subscript domain of the variable;
+\item[\hspace*{54pt}] {\it attrib}, \dots, {\it attrib} are optional
+attributes of the variable. (Commae preceding attributes may be
+omitted.)
+\end{description}
+
+\noindent Optional attributes:
+
+\begin{description}
+\item[{\tt integer}\hspace*{18.5pt}] restricts the variable to be
+integer;
+\item[{\tt binary}\hspace*{24pt}] restricts the variable to be binary;
+\item[{\tt>=} {\it expression}]\hspace*{0pt}\\
+specifies an lower bound of the variable;
+\item[{\tt<=} {\it expression}]\hspace*{0pt}\\
+specifies an upper bound of the variable;
+\item[{\tt=} {\it expression}]\hspace*{0pt}\\
+specifies a fixed value of the variable;
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+var x >= 0;
+var y{I,J};
+var make{p in prd}, integer, >= commit[p], <= market[p];
+var store{raw, 1..T+1} >= 0;
+var z{i in I, j in J} >= i+j;
+\end{verbatim}
+
+The variable statement declares a variable. If a subscript domain is
+not specified, the variable is a simple (scalar) variable, otherwise it
+is a $n$-dimensional array of elemental variables.
+
+Elemental variable(s) associated with the model variable (if it is a
+simple variable) or its members (if it is an array) correspond to the
+variables in the LP/MIP problem formulation (see Subsection
+\ref{problem}, page \pageref{problem}). Note that only elemental
+variables actually referenced in some constraints and/or objectives are
+included in the LP/MIP problem instance to be generated.
+
+The type attributes {\tt integer} and {\tt binary} restrict the
+variable to be integer or binary, respectively. If no type attribute is
+specified, the variable is continuous. If all variables in the model
+are continuous, the corresponding problem is of LP class. If there is
+at least one integer or binary variable, the problem is of MIP class.
+
+The lower bound ({\tt>=}) attribute specifies a numeric expression for
+computing an lower bound of the variable. At most one lower bound can
+be specified. By default all variables (except binary ones) have no
+lower bound, so if a variable is required to be non-negative, its zero
+lower bound should be explicitly specified.
+
+The upper bound ({\tt<=}) attribute specifies a numeric expression for
+computing an upper bound of the variable. At most one upper bound
+attribute can be specified.
+
+The fixed value ({\tt=}) attribute specifies a numeric expression for
+computing a value, at which the variable is fixed. This attribute
+cannot be specified along with the bound attributes.
+
+\subsection{Constraint statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][96pt]{345pt}{
+\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
+{\it expression} {\tt,} {\tt=} {\it expression} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
+{\it expression} {\tt,} {\tt<=} {\it expression} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
+{\it expression} {\tt,} {\tt>=} {\it expression} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
+{\it expression} {\tt,} {\tt<=} {\it expression} {\tt,} {\tt<=}
+{\it expression} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt s.t.} {\it name} {\it alias} {\it domain} {\tt:}
+{\it expression} {\tt,} {\tt>=} {\it expression} {\tt,} {\tt>=}
+{\it expression} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+constraint;
+\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
+specifies an alias of the constraint;
+\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
+which specifies a subscript domain of the constraint;
+\item[\hspace*{54pt}] {\it expression} is a linear expression used to
+compute a component of the constraint. (Commae following expressions
+may be omitted.)
+\end{description}
+
+\begin{description}
+\item[{\rm Note:}\hspace*{31pt}] The keyword {\tt s.t.} may be written
+as {\tt subject to} or as {\tt subj to}, or may be omitted at all.
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+s.t. r: x + y + z, >= 0, <= 1;
+limit{t in 1..T}: sum{j in prd} make[j,t] <= max_prd;
+subject to balance{i in raw, t in 1..T}: store[i,t+1] -
+   store[i,t] - sum{j in prd} units[i,j] * make[j,t];
+subject to rlim 'regular-time limit' {t in time}:
+sum{p in prd} pt[p] * rprd[p,t] <= 1.3 * dpp[t] * crews[t];
+\end{verbatim}
+
+The constraint statement declares a constraint. If a subscript domain
+is not specified, the constraint is a simple (scalar) constraint,
+otherwise it is a $n$-dimensional array of elemental constraints.
+
+Elemental constraint(s) associated with the model constraint (if it is
+a simple constraint) or its members (if it is an array) correspond to
+the linear constraints in the LP/MIP problem formulation (see
+Subsection \ref{problem}, page \pageref{problem}).
+
+If the constraint has the form of equality or single inequality, i.e.
+includes two expressions, one of which follows the colon and other
+follows the relation sign {\tt=}, {\tt<=}, or {\tt>=}, both expressions
+in the statement can be linear expressions. If the constraint has the
+form of double inequality, i.e. includes three expressions, the middle
+expression can be a linear expression while the leftmost and rightmost
+ones can be only numeric expressions.
+
+Generating the model is, roughly speaking, generating its constraints,
+which are always evaluated for the entire subscript domain. Evaluation
+of the constraints leads, in turn, to evaluation of other model objects
+such as sets, parameters, and variables.
+
+Constructing an actual linear constraint included in the problem
+instance, which (constraint) corresponds to a particular elemental
+constraint, is performed as follows.
+
+If the constraint has the form of equality or single inequality,
+evaluation of both linear expressions gives two resultant linear forms:
+$$\begin{array}{r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r@{\ }c@{\ }r}
+f&=&a_1x_1&+&a_2x_2&+\dots+&a_nx_n&+&a_0,\\
+g&=&b_1x_1&+&a_2x_2&+\dots+&a_nx_n&+&b_0,\\
+\end{array}$$
+where $x_1$, $x_2$, \dots, $x_n$ are elemental variables; $a_1$, $a_2$,
+\dots, $a_n$, $b_1$, $b_2$, \dots, $b_n$ are numeric coefficients;
+$a_0$ and $b_0$ are constant terms. Then all linear terms of $f$ and
+$g$ are carried to the left-hand side, and the constant terms are
+carried to the right-hand side, that gives the final elemental
+constraint in the standard form:
+$$(a_1-b_1)x_1+(a_2-b_2)x_2+\dots+(a_n-b_n)x_n\left\{
+\begin{array}{@{}c@{}}=\\\leq\\\geq\\\end{array}\right\}b_0-a_0.$$
+
+If the constraint has the form of double inequality, evaluation of the
+middle linear expression gives the resultant linear form:
+$$f=a_1x_1+a_2x_2+\dots+a_nx_n+a_0,$$
+and evaluation of the leftmost and rightmost numeric expressions gives
+two numeric values $l$ and $u$, respectively. Then the constant term of
+the linear form is carried to both left-hand and right-handsides that
+gives the final elemental constraint in the standard form:
+$$l-a_0\leq a_1x_1+a_2x_2+\dots+a_nx_n\leq u-a_0.$$
+
+\subsection{Objective statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][44pt]{345pt}{
+\hspace{6pt} {\tt minimize} {\it name} {\it alias} {\it domain} {\tt:}
+{\it expression} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt maximize} {\it name} {\it alias} {\it domain} {\tt:}
+{\it expression} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+objective;
+\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
+specifies an alias of the objective;
+\item[\hspace*{54pt}] {\it domain} is an optional indexing expression,
+which specifies a subscript domain of the objective;
+\item[\hspace*{54pt}] {\it expression} is a linear expression used to
+compute the linear form of the objective.
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+minimize obj: x + 1.5 * (y + z);
+maximize total_profit: sum{p in prd} profit[p] * make[p];
+\end{verbatim}
+
+The objective statement declares an objective. If a subscript domain is
+not specified, the objective is a simple (scalar) objective. Otherwise
+it is a $n$-dimensional array of elemental objectives.
+
+Elemental objective(s) associated with the model objective (if it is a
+simple objective) or its members (if it is an array) correspond to
+general linear constraints in the LP/MIP problem formulation (see
+Subsection \ref{problem}, page \pageref{problem}). However, unlike
+constraints the corresponding linear forms are free (unbounded).
+
+Constructing an actual linear constraint included in the problem
+instance, which (constraint) corresponds to a particular elemental
+constraint, is performed as follows. The linear expression specified in
+the objective statement is evaluated that, gives the resultant linear
+form:
+$$f=a_1x_1+a_2x_2+\dots+a_nx_n+a_0,$$
+where $x_1$, $x_2$, \dots, $x_n$ are elemental variables; $a_1$, $a_2$,
+\dots, $a_n$ are numeric coefficients; $a_0$ is the constant term. Then
+the linear form is used to construct the final elemental constraint in
+the standard form:
+$$-\infty<a_1x_1+a_2x_2+\dots+a_nx_n+a_0<+\infty.$$
+
+As a rule the model description contains only one objective statement
+that defines the objective function used in the problem instance.
+However, it is allowed to declare arbitrary number of objectives, in
+which case the actual objective function is the first objective
+encountered in the model description. Other objectives are also
+included in the problem instance, but they do not affect the objective
+function.
+
+\subsection{Solve statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][24pt]{345pt}{
+\hspace{6pt} {\tt solve} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Note:}\hspace*{31pt}] The solve statement is optional and
+can be used only once. If no solve statement is used, one is assumed at
+the end of the model section.
+\end{description}
+
+The solve statement causes the model to be solved, that means computing
+numeric values of all model variables. This allows using variables in
+statements below the solve statement in the same way as if they were
+numeric parameters.
+
+Note that the variable, constraint, and objective statements cannot be
+used below the solve statement, i.e. all principal components of the
+model must be declared above the solve statement.
+
+\subsection{Check statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][24pt]{345pt}{
+\hspace{6pt} {\tt check} {\it domain} {\tt:} {\it expression} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
+expression, which specifies a subscript domain of the check statement;
+\item[\hspace*{54pt}] {\it expression} is an logical expression which
+specifies the logical condition to be checked. (The colon preceding
+{\it expression} may be omitted.)
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+check: x + y <= 1 and x >= 0 and y >= 0;
+check sum{i in ORIG} supply[i] = sum{j in DEST} demand[j];
+check{i in I, j in 1..10}: S[i,j] in U[i] union V[j];
+\end{verbatim}
+
+The check statement allows checking the resultant value of an logical
+expression specified in the statement. If the value is {\it false}, an
+error is reported.
+
+If the subscript domain is not specified, the check is performed only
+once. Specifying the subscript domain allows performing multiple checks
+for every\linebreak $n$-tuple in the domain set. In the latter case the
+logical expression may include dummy indices introduced in
+corresponding indexing expression.
+
+\subsection{Display statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][24pt]{345pt}{
+\hspace{6pt} {\tt display} {\it domain} {\tt:} {\it item} {\tt,}
+\dots {\tt,} {\it item} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
+expression, which specifies a subscript domain of the check statement;
+\item[\hspace*{54pt}] {\it item}, \dots, {\it item} are items to be
+displayed. (The colon preceding the first item may be omitted.)
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+display: 'x =', x, 'y =', y, 'z =', z;
+display sqrt(x ** 2 + y ** 2 + z ** 2);
+display{i in I, j in J}: i, j, a[i,j], b[i,j];
+\end{verbatim}
+
+\newpage
+
+The display statement evaluates all items specified in the statement
+and writes their values to the terminal in plain text format.
+
+If a subscript domain is not specified, items are evaluated and then
+displayed only once. Specifying the subscript domain causes items to be
+evaluated and displayed for every $n$-tuple in the domain set. In the
+latter case items may include dummy indices introduced in corresponding
+indexing expression.
+
+An item to be displayed can be a model object (set, parameter, variable,
+constraint, objective) or an expression.
+
+If the item is a computable object (i.e. a set or parameter provided
+with the assign attribute), the object is evaluated over the entire
+domain and then its content (i.e. the content of the object array) is
+displayed. Otherwise, if the item is not a computable object, only its
+current content (i.e. members actually generated during the model
+evaluation) is displayed.
+
+If the item is an expression, the expression is evaluated and its
+resultant value is displayed.
+
+\subsection{Printf statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][60pt]{345pt}{
+\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
+{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
+{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt>}
+{\it filename} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt printf} {\it domain} {\tt:} {\it format} {\tt,}
+{\it expression} {\tt,} \dots {\tt,} {\it expression} {\tt>>}
+{\it filename} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an optional indexing
+expression, which specifies a subscript domain of the printf statement;
+\item[\hspace*{54pt}] {\it format} is a symbolic expression whose value
+specifies a format control string. (The colon preceding the format
+expression may be omitted.)
+\item[\hspace*{54pt}] {\it expression}, \dots, {\it expression} are
+zero or more expressions whose values have to be formatted and printed.
+Each expression must be of numeric, symbolic, or logical type.
+\item[\hspace*{54pt}] {\it filename} is a symbolic expression whose
+value specifies a name of a text file, to which the output is
+redirected. The flag {\tt>} means creating a new empty file while the
+flag {\tt>>} means appending the output to an existing file. If no file
+name is specified, the output is written to the terminal.
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+printf 'Hello, world!\n';
+printf: "x = %.3f; y = %.3f; z = %.3f\n",
+   x, y, z > "result.txt";
+printf{i in I, j in J}: "flow from %s to %s is %d\n",
+   i, j, x[i,j] >> result_file & ".txt";
+\end{verbatim}
+
+\newpage
+
+\begin{verbatim}
+printf{i in I} 'total flow from %s is %g\n',
+   i, sum{j in J} x[i,j];
+printf{k in K} "x[%s] = " & (if x[k] < 0 then "?" else "%g"),
+   k, x[k];
+\end{verbatim}
+
+The printf statement is similar to the display statement, however, it
+allows formatting data to be written.
+
+If a subscript domain is not specified, the printf statement is
+executed only once. Specifying a subscript domain causes executing the
+printf statement for every $n$-tuple in the domain set. In the latter
+case the format and expression may include dummy indices introduced in
+corresponding indexing expression.
+
+The format control string is a value of the symbolic expression
+{\it format} specified in the printf statement. It is composed of zero
+or more directives as follows: ordinary characters (not {\tt\%}), which
+are copied unchanged to the output stream, and conversion
+specifications, each of which causes evaluating corresponding
+expression specified in the printf statement, formatting it, and
+writing its resultant value to the output stream.
+
+Conversion specifications that may be used in the format control string
+are the following: {\tt d}, {\tt i}, {\tt f}, {\tt F}, {\tt e}, {\tt E},
+{\tt g}, {\tt G}, and {\tt s}. These specifications have the same
+syntax and semantics as in the C programming language.
+
+\subsection{For statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][44pt]{345pt}{
+\hspace{6pt} {\tt for} {\it domain} {\tt:} {\it statement} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt for} {\it domain} {\tt:} {\tt\{} {\it statement}
+\dots {\it statement} {\tt\}} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it domain} is an indexing
+expression which specifies a subscript domain of the for statement.
+(The colon following the indexing expression may be omitted.)
+\item[\hspace*{54pt}] {\it statement} is a statement, which should be
+executed under control of the for statement;
+\item[\hspace*{54pt}] {\it statement}, \dots, {\it statement} is a
+sequence of statements (enclosed in curly braces), which should be
+executed under control of the for statement.
+\end{description}
+
+\begin{description}
+\item[{\rm Note:}\hspace*{31pt}] Only the following statements can be
+used within the for statement: check, display, printf, and another for.
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+for {(i,j) in E: i != j}
+{  printf "flow from %s to %s is %g\n", i, j, x[i,j];
+   check x[i,j] >= 0;
+}
+\end{verbatim}
+
+\newpage
+
+\begin{verbatim}
+for {i in 1..n}
+{  for {j in 1..n} printf " %s", if x[i,j] then "Q" else ".";
+   printf("\n");
+}
+for {1..72} printf("*");
+\end{verbatim}
+
+The for statement causes a statement or a sequence of statements
+specified as part of the for statement to be executed for every
+$n$-tuple in the domain set. Thus, statements within the for statement
+may include dummy indices introduced in corresponding indexing
+expression.
+
+\subsection{Table statement}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][68pt]{345pt}{
+\hspace{6pt} {\tt table} {\it name} {\it alias} {\tt IN} {\it driver}
+{\it arg} \dots {\it arg} {\tt:}
+
+\hspace{6pt} {\tt\ \ \ \ \ } {\it set} {\tt<-} {\tt[} {\it fld} {\tt,}
+\dots {\tt,} {\it fld} {\tt]} {\tt,} {\it par} {\tt\textasciitilde}
+{\it fld} {\tt,} \dots {\tt,} {\it par} {\tt\textasciitilde} {\it fld}
+{\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt table} {\it name} {\it alias} {\it domain} {\tt OUT}
+{\it driver} {\it arg} \dots {\it arg} {\tt:}
+
+\hspace{6pt} {\tt\ \ \ \ \ } {\it expr} {\tt\textasciitilde} {\it fld}
+{\tt,} \dots {\tt,} {\it expr} {\tt\textasciitilde} {\it fld} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+table;
+\item[\hspace*{54pt}] {\it alias} is an optional string literal, which
+specifies an alias of the table;
+\item[\hspace*{54pt}] {\it domain} is an indexing expression, which
+specifies a subscript domain of the (output) table;
+\item[\hspace*{54pt}] {\tt IN} means reading data from the input table;
+\item[\hspace*{54pt}] {\tt OUT} means writing data to the output table;
+\item[\hspace*{54pt}] {\it driver} is a symbolic expression, which
+specifies the driver used to access the table (for details see Section
+\ref{drivers}, page \pageref{drivers});
+\item[\hspace*{54pt}] {\it arg} is an optional symbolic expression,
+which is an argument pass\-ed to the table driver. This symbolic
+expression must not include dummy indices specified in the domain;
+\item[\hspace*{54pt}] {\it set} is the name of an optional simple set
+called {\it control set}. It can be omitted along with the delimiter
+{\tt<-};
+\item[\hspace*{54pt}] {\it fld} is a field name. Within square brackets
+at least one field should be specified. The field name following
+a parameter name or expression is optional and can be omitted along
+with the delimiter {\tt\textasciitilde}, in which case the name of
+corresponding model object is used as the field name;
+\item[\hspace*{54pt}] {\it par} is a symbolic name of a model parameter;
+\item[\hspace*{54pt}] {\it expr} is a numeric or symbolic expression.
+\end{description}
+
+\newpage
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+table data IN "CSV" "data.csv":
+   S <- [FROM,TO], d~DISTANCE, c~COST;
+table result{(f,t) in S} OUT "CSV" "result.csv":
+   f~FROM, t~TO, x[f,t]~FLOW;
+\end{verbatim}
+
+The table statement allows reading data from a table into model
+objects such as sets and (non-scalar) parameters as well as writing
+data from the model to a table.
+
+\subsubsection{Table structure}
+
+A {\it data table} is an (unordered) set of {\it records}, where each
+record consists of the same number of {\it fields}, and each field is
+provided with a unique symbolic name called the {\it field name}. For
+example:
+
+\bigskip
+
+\begin{tabular}{@{\hspace*{38mm}}c@{\hspace*{11mm}}c@{\hspace*{10mm}}c
+@{\hspace*{9mm}}c}
+First&Second&&Last\\
+field&field&.\ \ .\ \ .&field\\
+$\downarrow$&$\downarrow$&&$\downarrow$\\
+\end{tabular}
+
+\begin{tabular}{ll@{}}
+Table header&$\rightarrow$\\
+First record&$\rightarrow$\\
+Second record&$\rightarrow$\\
+\\
+\hfil .\ \ .\ \ .\\
+\\
+Last record&$\rightarrow$\\
+\end{tabular}
+\begin{tabular}{|l|l|c|c|}
+\hline
+{\tt FROM}&{\tt TO}&{\tt DISTANCE}&{\tt COST}\\
+\hline
+{\tt Seattle}  &{\tt New-York}&{\tt 2.5}&{\tt 0.12}\\
+{\tt Seattle}  &{\tt Chicago} &{\tt 1.7}&{\tt 0.08}\\
+{\tt Seattle}  &{\tt Topeka}  &{\tt 1.8}&{\tt 0.09}\\
+{\tt San-Diego}&{\tt New-York}&{\tt 2.5}&{\tt 0.15}\\
+{\tt San-Diego}&{\tt Chicago} &{\tt 1.8}&{\tt 0.10}\\
+{\tt San-Diego}&{\tt Topeka}  &{\tt 1.4}&{\tt 0.07}\\
+\hline
+\end{tabular}
+
+\subsubsection{Reading data from input table}
+
+The input table statement causes reading data from the specified table
+record by record.
+
+Once a next record has been read, numeric or symbolic values of fields,
+whose names are enclosed in square brackets in the table statement, are
+gathered into $n$-tuple, and if the control set is specified in the
+table statement, this $n$-tuple is added to it. Besides, a numeric or
+symbolic value of each field associated with a model parameter is
+assigned to the parameter member identified by subscripts, which are
+components of the $n$-tuple just read.
+
+For example, the following input table statement:
+
+\medskip
+
+\noindent\hfil
+\verb|table data IN "...": S <- [FROM,TO], d~DISTANCE, c~COST;|
+
+\medskip
+
+\noindent
+causes reading values of four fields named {\tt FROM}, {\tt TO},
+{\tt DISTANCE}, and {\tt COST} from each record of the specified table.
+Values of fields {\tt FROM} and {\tt TO} give a pair $(f,t)$, which is
+added to the control set {\tt S}. The value of field {\tt DISTANCE} is
+assigned to parameter member ${\tt d}[f,t]$, and the value of field
+{\tt COST} is assigned to parameter member ${\tt c}[f,t]$.
+
+Note that the input table may contain extra fields whose names are not
+specified in the table statement, in which case values of these fields
+on reading the table are ignored.
+
+\subsubsection{Writing data to output table}
+
+The output table statement causes writing data to the specified table.
+Note that some drivers (namely, CSV and xBASE) destroy the output table
+before writing data, i.e. delete all its existing records.
+
+Each $n$-tuple in the specified domain set generates one record written
+to the output table. Values of fields are numeric or symbolic values of
+corresponding expressions specified in the table statement. These
+expressions are evaluated for each $n$-tuple in the domain set and,
+thus, may include dummy indices introduced in the corresponding indexing
+expression.
+
+For example, the following output table statement:
+
+\medskip
+
+\noindent
+\verb|   table result{(f,t) in S} OUT "...": f~FROM, t~TO, x[f,t]~FLOW;|
+
+\medskip
+
+\noindent
+causes writing records, by one record for each pair $(f,t)$ in set
+{\tt S}, to the output table, where each record consists of three
+fields named {\tt FROM}, {\tt TO}, and {\tt FLOW}. The values written
+to fields {\tt FROM} and {\tt TO} are current values of dummy indices
+{\tt f} and {\tt t}, and the value written to field {\tt FLOW} is
+a value of member ${\tt x}[f,t]$ of corresponding subscripted parameter
+or variable.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Model data}
+
+{\it Model data} include elemental sets, which are ``values'' of model
+sets, and numeric and symbolic values of model parameters.
+
+In MathProg there are two different ways to saturate model sets and
+parameters with data. One way is simply providing necessary data using
+the assign attribute. However, in many cases it is more practical to
+separate the model itself and particular data needed for the model. For
+the latter reason in MathProg there is another way, when the model
+description is divided into two parts: model section and data section.
+
+A {\it model section} is a main part of the model description that
+contains declarations of all model objects and is common for all
+problems based on that model.
+
+A {\it data section} is an optional part of the model description that
+contains model data specific for a particular problem.
+
+In MathProg model and data sections can be placed either in one text
+file or in two separate text files.
+
+1. If both model and data sections are placed in one file, the file is
+composed as follows:
+
+\bigskip
+
+\noindent\hfil
+\framebox{\begin{tabular}{l}
+{\it statement}{\tt;}\\
+{\it statement}{\tt;}\\
+\hfil.\ \ .\ \ .\\
+{\it statement}{\tt;}\\
+{\tt data;}\\
+{\it data block}{\tt;}\\
+{\it data block}{\tt;}\\
+\hfil.\ \ .\ \ .\\
+{\it data block}{\tt;}\\
+{\tt end;}
+\end{tabular}}
+
+\bigskip
+
+2. If the model and data sections are placed in two separate files, the
+files are composed as follows:
+
+\bigskip
+
+\noindent\hfil
+\begin{tabular}{@{}c@{}}
+\framebox{\begin{tabular}{l}
+{\it statement}{\tt;}\\
+{\it statement}{\tt;}\\
+\hfil.\ \ .\ \ .\\
+{\it statement}{\tt;}\\
+{\tt end;}\\
+\end{tabular}}\\
+\\\\Model file\\
+\end{tabular}
+\hspace{32pt}
+\begin{tabular}{@{}c@{}}
+\framebox{\begin{tabular}{l}
+{\tt data;}\\
+{\it data block}{\tt;}\\
+{\it data block}{\tt;}\\
+\hfil.\ \ .\ \ .\\
+{\it data block}{\tt;}\\
+{\tt end;}\\
+\end{tabular}}\\
+\\Data file\\
+\end{tabular}
+
+\bigskip
+
+\begin{description}
+\item[{\rm Note:}\hspace*{31pt}] If the data section is placed in a
+separate file, the keyword {\tt data} is optional and may be omitted
+along with the semicolon that follows it.
+\end{description}
+
+\subsection{Coding data section}
+
+The {\it data section} is a sequence of data blocks in various formats,
+which are discussed in following subsections. The order, in which data
+blocks follow in the data section, may be arbitrary, not necessarily
+the same, in which corresponding model objects follow in the model
+section.
+
+The rules of coding the data section are commonly the same as the rules
+of coding the model description (see Subsection \ref{coding}, page
+\pageref{coding}), i.e. data blocks are composed from basic lexical
+units such as symbolic names, numeric and string literals, keywords,
+delimiters, and comments. However, for the sake of convenience and
+improving readability there is one deviation from the common rule: if
+a string literal consists of only alphanumeric characters (including
+the underscore character), the signs {\tt+} and {\tt-}, and/or the
+decimal point, it may be coded without bordering by (single or double)
+quotes.
+
+All numeric and symbolic material provided in the data section is coded
+in the form of numbers and symbols, i.e. unlike the model section
+no expressions are allowed in the data section. Nevertheless, the signs
+{\tt+} and {\tt-} can precede numeric literals to allow coding signed
+numeric quantities, in which case there must be no white-space
+characters between the sign and following numeric literal (if there is
+at least one white-space, the sign and following numeric literal are
+recognized as two different lexical units).
+
+\subsection{Set data block}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][44pt]{345pt}{
+\hspace{6pt} {\tt set} {\it name} {\tt,} {\it record} {\tt,} \dots
+{\tt,} {\it record} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt set} {\it name} {\tt[} {\it symbol} {\tt,} \dots
+{\tt,} {\it symbol} {\tt]} {\tt,} {\it record} {\tt,} \dots {\tt,}
+{\it record} {\tt;}
+}}
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+set;
+\item[\hspace*{54pt}] {\it symbol}, \dots, {\it symbol} are subscripts,
+which specify a particular member of the set (if the set is an array,
+i.e. a set of sets);
+\item[\hspace*{54pt}] {\it record}, \dots, {\it record} are data
+records.
+\end{description}
+
+\begin{description}
+\item[{\rm Note:}\hspace*{31pt}] Commae preceding data records may be
+omitted.
+\end{description}
+
+\noindent Data records:
+
+\begin{description}
+\item[{\tt :=}\hspace*{45pt}] is a non-significant data record, which
+may be used freely to improve readability;
+\item[{\tt(} {\it slice} {\tt)}\hspace*{18.5pt}] specifies a slice;
+\item[{\it simple-data}\hspace*{5.5pt}] specifies set data in the
+simple format;
+\item[{\tt:} {\it matrix-data}]\hspace*{0pt}\\
+specifies set data in the matrix format;
+\item[{\tt(tr)} {\tt:} {\it matrix-data}]\hspace*{0pt}\\
+specifies set data in the transposed matrix format. (In this case the
+colon following the keyword {\tt(tr)} may be omitted.)
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+set month := Jan Feb Mar Apr May Jun;
+set month "Jan", "Feb", "Mar", "Apr", "May", "Jun";
+set A[3,Mar] := (1,2) (2,3) (4,2) (3,1) (2,2) (4,4) (3,4);
+set A[3,'Mar'] := 1 2 2 3 4 2 3 1 2 2 4 4 2 4;
+set A[3,'Mar'] : 1 2 3 4 :=
+               1 - + - -
+               2 - + + -
+               3 + - - +
+               4 - + - + ;
+set B := (1,2,3) (1,3,2) (2,3,1) (2,1,3) (1,2,2) (1,1,1) (2,1,1);
+set B := (*,*,*) 1 2 3, 1 3 2, 2 3 1, 2 1 3, 1 2 2, 1 1 1, 2 1 1;
+set B := (1,*,2) 3 2 (2,*,1) 3 1 (1,2,3) (2,1,3) (1,1,1);
+set B := (1,*,*) : 1 2 3 :=
+                 1 + - -
+                 2 - + +
+                 3 - + -
+         (2,*,*) : 1 2 3 :=
+                 1 + - +
+                 2 - - -
+                 3 + - - ;
+\end{verbatim}
+
+\noindent(In these examples {\tt month} is a simple set of singlets,
+{\tt A} is a 2-dimensional array of doublets, and {\tt B} is a simple
+set of triplets. Data blocks for the same set are equivalent in the
+sense that they specify the same data in different formats.)
+
+\medskip
+
+The {\it set data block} is used to specify a complete elemental set,
+which is assigned to a set (if it is a simple set) or one of its
+members (if the set is an array of sets).\footnote{There is another way
+to specify data for a simple set along with data for parameters. This
+feature is discussed in the next subsection.}
+
+Data blocks can be specified only for non-computable sets, i.e. for
+sets, which have no assign ({\tt:=}) attribute in the corresponding set
+statements.
+
+If the set is a simple set, only its symbolic name should be specified
+in the header of the data block. Otherwise, if the set is a
+$n$-dimensional array, its symbolic name should be provided with a
+complete list of subscripts separated by commae and enclosed in square
+brackets to specify a particular member of the set array. The number of
+subscripts must be the same as the dimension of the set array, where
+each subscript must be a number or symbol.
+
+An elemental set defined in the set data block is coded as a sequence
+of data records described below.\footnote{{\it Data record} is simply a
+technical term. It does not mean that data records have any special
+formatting.}
+
+\newpage
+
+\subsubsection{Assign data record}
+
+The {\it assign} ({\tt:=}) {\it data record} is a non-signficant
+element. It may be used for improving readability of data blocks.
+
+\subsubsection{Slice data record}
+
+The {\it slice data record} is a control record, which specifies a
+{\it slice} of the elemental set defined in the data block. It has the
+following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\tt(} $s_1$ {\tt,} $s_2$ {\tt,} \dots {\tt,} $s_n$ {\tt)}
+
+\medskip
+
+\noindent where $s_1$, $s_2$, \dots, $s_n$ are components of the slice.
+
+Each component of the slice can be a number or symbol or the asterisk
+({\tt*}). The number of components in the slice must be the same as the
+dimension of $n$-tuples in the elemental set to be defined. For
+instance, if the elemental set contains 4-tuples (quadruplets), the
+slice must have four components. The number of asterisks in the slice
+is called the {\it slice dimension}.
+
+The effect of using slices is the following. If a $m$-dimensional slice
+(i.e. a slice having $m$ asterisks) is specified in the data block, all
+subsequent data records must specify tuples of the dimension $m$.
+Whenever a $m$-tuple is encountered, each asterisk in the slice is
+replaced by corresponding components of the $m$-tuple that gives the
+resultant $n$-tuple, which is included in the elemental set to be
+defined. For example, if the slice $(a,*,1,2,*)$ is in effect, and
+2-tuple $(3,b)$ is encountered in a subsequent data record, the
+resultant 5-tuple included in the elemental set is $(a,3,1,2,b)$.
+
+The slice having no asterisks itself defines a complete $n$-tuple,
+which is included in the elemental set.
+
+Being once specified the slice effects until either a new slice or the
+end of data block is encountered. Note that if no slice is specified in
+the data block, one, components of which are all asterisks, is assumed.
+
+\subsubsection{Simple data record}
+
+The {\it simple data record} defines one $n$-tuple in a simple format
+and has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+$t_1$ {\tt,} $t_2$ {\tt,} \dots {\tt,} $t_n$
+
+\medskip
+
+\noindent where $t_1$, $t_2$, \dots, $t_n$ are components of the
+$n$-tuple. Each component can be a number or symbol. Commae between
+components are optional and may be omitted.
+
+\subsubsection{Matrix data record}
+
+The {\it matrix data record} defines several 2-tuples (doublets) in
+a matrix format and has the following syntactic form:
+
+\newpage
+
+$$\begin{array}{cccccc}
+\mbox{{\tt:}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
+r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
+r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
+\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
+r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
+\end{array}$$
+where $r_1$, $r_2$, \dots, $r_m$ are numbers and/or symbols
+corresponding to rows of the matrix; $c_1$, $c_2$, \dots, $c_n$ are
+numbers and/or symbols corresponding to columns of the matrix, $a_{11}$,
+$a_{12}$, \dots, $a_{mn}$ are matrix elements, which can be either
+{\tt+} or {\tt-}. (In this data record the delimiter {\tt:} preceding
+the column list and the delimiter {\tt:=} following the column list
+cannot be omitted.)
+
+Each element $a_{ij}$ of the matrix data block (where $1\leq i\leq m$,
+$1\leq j\leq n$) corresponds to 2-tuple $(r_i,c_j)$. If $a_{ij}$ is the
+plus sign ({\tt+}), that 2-tuple (or a longer $n$-tuple, if a slice is
+used) is included in the elemental set. Otherwise, if $a_{ij}$ is the
+minus sign ({\tt-}), that 2-tuple is not included in the elemental set.
+
+Since the matrix data record defines 2-tuples, either the elemental set
+must consist of 2-tuples or the slice currently used must be
+2-dimensional.
+
+\subsubsection{Transposed matrix data record}
+
+The {\it transposed matrix data record} has the following syntactic
+form:
+$$\begin{array}{cccccc}
+\mbox{{\tt(tr) :}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
+r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
+r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
+\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
+r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
+\end{array}$$
+(In this case the delimiter {\tt:} following the keyword {\tt(tr)} is
+optional and may be omitted.)
+
+This data record is completely analogous to the matrix data record (see
+above) with only exception that in this case each element $a_{ij}$ of
+the matrix corresponds to 2-tuple $(c_j,r_i)$ rather than $(r_i,c_j)$.
+
+Being once specified the {\tt(tr)} indicator affects all subsequent
+data records until either a slice or the end of data block is
+encountered.
+
+\subsection{Parameter data block}
+
+\medskip
+
+\framebox[345pt][l]{
+\parbox[c][80pt]{345pt}{
+\hspace{6pt} {\tt param} {\it name} {\tt,} {\it record} {\tt,} \dots
+{\tt,} {\it record} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt param} {\it name} {\tt default} {\it value} {\tt,}
+{\it record} {\tt,} \dots {\tt,} {\it record} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt param} {\tt:} {\it tabbing-data} {\tt;}
+
+\medskip
+
+\hspace{6pt} {\tt param} {\tt default} {\it value} {\tt:}
+{\it tabbing-data} {\tt;}
+}}
+
+\newpage
+
+\setlength{\leftmargini}{60pt}
+
+\begin{description}
+\item[{\rm Where:}\hspace*{23pt}] {\it name} is a symbolic name of the
+parameter;
+\item[\hspace*{54pt}] {\it value} is an optional default value of the
+parameter;
+\item[\hspace*{54pt}] {\it record}, \dots, {\it record} are data
+records;
+\item[\hspace*{54pt}] {\it tabbing-data} specifies parameter data in
+the tabbing format.
+\end{description}
+
+\begin{description}
+\item[{\rm Note:}\hspace*{31pt}] Commae preceding data records may be
+omitted.
+\end{description}
+
+\noindent Data records:
+
+\begin{description}
+\item[{\tt :=}\hspace*{45pt}] is a non-significant data record, which
+may be used freely to improve readability;
+\item[{\tt[} {\it slice} {\tt]}\hspace*{18.5pt}] specifies a slice;
+\item[{\it plain-data}\hspace*{11pt}] specifies parameter data in the
+plain format;
+\item[{\tt:} {\it tabular-data}]\hspace*{0pt}\\
+specifies parameter data in the tabular format;
+\item[{\tt(tr)} {\tt:} {\it tabular-data}]\hspace*{0pt}\\
+specifies set data in the transposed tabular format. (In this case the
+colon following the keyword {\tt(tr)} may be omitted.)
+\end{description}
+
+\noindent{\bf Examples}
+
+\begin{verbatim}
+param T := 4;
+param month := 1 'Jan' 2 'Feb' 3 'Mar' 4 'Apr' 5 'May';
+param month := [1] Jan, [2] Feb, [3] Mar, [4] Apr, [5] May;
+param day := [Sun] 0, [Mon] 1, [Tue] 2, [Wed] 3, [Thu] 4,
+             [Fri] 5, [Sat] 6;
+param init_stock := iron 7.32 nickel 35.8;
+param init_stock [*] iron 7.32, nickel 35.8;
+param cost [iron] .025 [nickel] .03;
+param value := iron -.1, nickel .02;
+param       : init_stock cost value :=
+      iron       7.32    .025  -.1
+      nickel    35.8     .03    .02 ;
+param : raw : init_stock cost value :=
+      iron       7.32    .025  -.1
+      nickel    35.8     .03    .02 ;
+param demand default 0 (tr)
+       :  FRA  DET  LAN  WIN  STL  FRE  LAF :=
+   bands  300   .   100   75   .   225  250
+   coils  500  750  400  250   .   850  500
+   plate  100   .    .    50  200   .   250 ;
+\end{verbatim}
+
+\newpage
+
+\begin{verbatim}
+param trans_cost :=
+   [*,*,bands]:  FRA  DET  LAN  WIN  STL  FRE  LAF :=
+         GARY     30   10    8   10   11   71    6
+         CLEV     22    7   10    7   21   82   13
+         PITT     19   11   12   10   25   83   15
+   [*,*,coils]:  FRA  DET  LAN  WIN  STL  FRE  LAF :=
+         GARY     39   14   11   14   16   82    8
+         CLEV     27    9   12    9   26   95   17
+         PITT     24   14   17   13   28   99   20
+   [*,*,plate]:  FRA  DET  LAN  WIN  STL  FRE  LAF :=
+         GARY     41   15   12   16   17   86    8
+         CLEV     29    9   13    9   28   99   18
+         PITT     26   14   17   13   31  104   20 ;
+\end{verbatim}
+
+The {\it parameter data block} is used to specify complete data for a
+parameter (or parameters, if data are specified in the tabbing format).
+
+Data blocks can be specified only for non-computable parameters, i.e.
+for parameters, which have no assign ({\tt:=}) attribute in the
+corresponding parameter statements.
+
+Data defined in the parameter data block are coded as a sequence of
+data records described below. Additionally the data block can be
+provided with the optional {\tt default} attribute, which specifies a
+default numeric or symbolic value of the parameter (parameters). This
+default value is assigned to the parameter or its members, if
+no appropriate value is defined in the parameter data block. The
+{\tt default} attribute cannot be used, if it is already specified in
+the corresponding parameter statement.
+
+\subsubsection{Assign data record}
+
+The {\it assign} ({\tt:=}) {\it data record} is a non-signficant
+element. It may be used for improving readability of data blocks.
+
+\subsubsection{Slice data record}
+
+The {\it slice data record} is a control record, which specifies a
+{\it slice} of the parameter array. It has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+{\tt[} $s_1$ {\tt,} $s_2$ {\tt,} \dots {\tt,} $s_n$ {\tt]}
+
+\medskip
+
+\noindent where $s_1$, $s_2$, \dots, $s_n$ are components of the slice.
+
+Each component of the slice can be a number or symbol or the asterisk
+({\tt*}). The number of components in the slice must be the same as the
+dimension of the parameter. For instance, if the parameter is a
+4-dimensional array, the slice must have four components. The number of
+asterisks in the slice is called the {\it slice dimension}.
+
+The effect of using slices is the following. If a $m$-dimensional slice
+(i.e. a slice having $m$ asterisks) is specified in the data block, all
+subsequent data records must specify subscripts of the parameter
+members as if the parameter were $m$-dimensional, not $n$-dimensional.
+
+Whenever $m$ subscripts are encountered, each asterisk in the slice is
+replaced by corresponding subscript that gives $n$ subscripts, which
+define the actual parameter member. For example, if the slice
+$[a,*,1,2,*]$ is in effect, and subscripts 3 and $b$ are encountered in
+a subsequent data record, the complete subscript list used to choose a
+parameter member is $[a,3,1,2,b]$.
+
+It is allowed to specify a slice having no asterisks. Such slice itself
+defines a complete subscript list, in which case the next data record
+should define only a single value of corresponding parameter member.
+
+Being once specified the slice effects until either a new slice or the
+end of data block is encountered. Note that if no slice is specified in
+the data block, one, components of which are all asterisks, is assumed.
+
+\subsubsection{Plain data record}
+
+The {\it plain data record} defines a subscript list and a single value
+in the plain format. This record has the following syntactic form:
+
+\medskip
+
+\noindent\hfil
+$t_1$ {\tt,} $t_2$ {\tt,} \dots {\tt,} $t_n$ {\tt,} $v$
+
+\medskip
+
+\noindent where $t_1$, $t_2$, \dots, $t_n$ are subscripts, and $v$ is a
+value. Each subscript as well as the value can be a number or symbol.
+Commae following subscripts are optional and may be omitted.
+
+In case of 0-dimensional parameter or slice the plain data record has
+no subscripts and consists of a single value only.
+
+\subsubsection{Tabular data record}
+
+The {\it tabular data record} defines several values, where each value
+is provided with two subscripts. This record has the following
+syntactic form:
+$$\begin{array}{cccccc}
+\mbox{{\tt:}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
+r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
+r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
+\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
+r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
+\end{array}$$
+where $r_1$, $r_2$, \dots, $r_m$ are numbers and/or symbols
+corresponding to rows of the table; $c_1$, $c_2$, \dots, $c_n$ are
+numbers and/or symbols corresponding to columns of the table, $a_{11}$,
+$a_{12}$, \dots, $a_{mn}$ are table elements. Each element can be a
+number or symbol or the single decimal point ({\tt.}). (In this data
+record the delimiter {\tt:} preceding the column list and the delimiter
+{\tt:=} following the column list cannot be omitted.)
+
+Each element $a_{ij}$ of the tabular data block ($1\leq i\leq m$,
+$1\leq j\leq n$) defines two subscripts, where the first subscript is
+$r_i$, and the second one is $c_j$. These subscripts are used in
+conjunction with the current slice to form the complete subscript list
+that identifies a particular member of the parameter array. If $a_{ij}$
+is a number or symbol, this value is assigned to the parameter member.
+However, if $a_{ij}$ is the single decimal point, the member is
+assigned a default value specified either in the parameter data block
+or in the parameter statement, or, if no default value is specified,
+the member remains undefined.
+
+Since the tabular data record provides two subscripts for each value,
+either the parameter or the slice currently used must be 2-dimensional.
+
+\subsubsection{Transposed tabular data record}
+
+The {\it transposed tabular data record} has the following syntactic
+form:
+$$\begin{array}{cccccc}
+\mbox{{\tt(tr) :}}&c_1&c_2&\dots&c_n&\mbox{{\tt:=}}\\
+r_1&a_{11}&a_{12}&\dots&a_{1n}&\\
+r_2&a_{21}&a_{22}&\dots&a_{2n}&\\
+\multicolumn{5}{c}{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}&\\
+r_m&a_{m1}&a_{m2}&\dots&a_{mn}&\\
+\end{array}$$
+(In this case the delimiter {\tt:} following the keyword {\tt(tr)} is
+optional and may be omitted.)
+
+This data record is completely analogous to the tabular data record
+(see above) with only exception that the first subscript defined by
+element $a_{ij}$ is $c_j$ while the second one is $r_i$.
+
+Being once specified the {\tt(tr)} indicator affects all subsequent
+data records until either a slice or the end of data block is
+encountered.
+
+\subsubsection{Tabbing data format}
+
+The parameter data block in the {\it tabbing format} has the following
+syntactic form:
+$$\begin{array}{p{12pt}@{\ }l@{\ }c@{\ }l@{\ }c@{\ }l@{\ }r@{\ }l@{\ }c
+@{\ }l@{\ }c@{\ }l@{\ }l}
+\multicolumn{7}{@{}c@{}}{\mbox{\tt param}\ \mbox{\tt default}\ \mbox
+{\it value}\ \mbox{\tt:}\ \mbox{\it s}\ \mbox{\tt:}}&
+p_1&\mbox{\tt,}&p_2&\mbox{\tt,} \dots \mbox{\tt,}&p_k&\mbox{\tt:=}\\
+&t_{11}&\mbox{\tt,}&t_{12}&\mbox{\tt,} \dots \mbox{\tt,}&t_{1n}&
+\mbox{\tt,}&a_{11}&\mbox{\tt,}&a_{12}&\mbox{\tt,} \dots \mbox{\tt,}&
+a_{1k}\\
+&t_{21}&\mbox{\tt,}&t_{22}&\mbox{\tt,} \dots \mbox{\tt,}&t_{2n}&
+\mbox{\tt,}&a_{21}&\mbox{\tt,}&a_{22}&\mbox{\tt,} \dots \mbox{\tt,}&
+a_{2k}\\
+\multicolumn{13}{c}
+{.\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .\ \ .}\\
+&t_{m1}&\mbox{\tt,}&t_{m2}&\mbox{\tt,} \dots \mbox{\tt,}&t_{mn}&
+\mbox{\tt,}&a_{m1}&\mbox{\tt,}&a_{m2}&\mbox{\tt,} \dots \mbox{\tt,}&
+a_{mk}&\mbox{\tt;}\\
+\end{array}$$
+
+{\it Notes:}
+
+1. The keyword {\tt default} may be omitted along with a value
+following it.
+
+2. Symbolic name {\tt s} may be omitted along with the colon following
+it.
+
+3. All comae are optional and may be omitted.
+
+\medskip
+
+The data block in the tabbing format shown above is exactly equivalent
+to the following data blocks for $j=1,2,\dots,k$:
+
+\medskip
+
+{\tt set} {\it s} {\tt:=}
+{\tt(}$t_{11}${\tt,}$t_{12}${\tt,}\dots{\tt,}$t_{1n}${\tt)}
+{\tt(}$t_{21}${\tt,}$t_{22}${\tt,}\dots{\tt,}$t_{2n}${\tt)} \dots
+{\tt(}$t_{m1}${\tt,}$t_{m2}${\tt,}\dots{\tt,}$t_{mn}${\tt)} {\tt;}
+
+{\tt param} $p_j$ {\tt default} {\it value} {\tt:=}
+
+$\!${\tt[}$t_{11}${\tt,}$t_{12}${\tt,}\dots{\tt,}$t_{1n}${\tt]}
+$a_{1j}$
+{\tt[}$t_{21}${\tt,}$t_{22}${\tt,}\dots{\tt,}$t_{2n}${\tt]} $a_{2j}$
+\dots
+{\tt[}$t_{m1}${\tt,}$t_{m2}${\tt,}\dots{\tt,}$t_{mn}${\tt]} $a_{mj}$
+{\tt;}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\appendix
+
+\newpage
+
+\section{Using suffixes}
+
+Suffixes can be used to retrieve additional values associated with
+model variables, constraints, and objectives.
+
+A {\it suffix} consists of a period ({\tt.}) followed by a non-reserved
+keyword. For example, if {\tt x} is a two-dimensional variable,
+{\tt x[i,j].lb} is a numeric value equal to the lower bound of
+elemental variable {\tt x[i,j]}, which (value) can be used everywhere
+in expressions like a numeric parameter.
+
+For model variables suffixes have the following meaning:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt.lb}&lower bound\\
+{\tt.ub}&upper bound\\
+{\tt.status}&status in the solution:\\
+&0 --- undefined\\
+&1 --- basic\\
+&2 --- non-basic on lower bound\\
+&3 --- non-basic on upper bound\\
+&4 --- non-basic free (unbounded) variable\\
+&5 --- non-basic fixed variable\\
+{\tt.val}&primal value in the solution\\
+{\tt.dual}&dual value (reduced cost) in the solution\\
+\end{tabular}
+
+\medskip
+
+For model constraints and objectives suffixes have the following
+meaning:
+
+\medskip
+
+\begin{tabular}{@{}p{96pt}p{222pt}@{}}
+{\tt.lb}&lower bound of the linear form\\
+{\tt.ub}&upper bound of the linear form\\
+{\tt.status}&status in the solution:\\
+&0 --- undefined\\
+&1 --- non-active\\
+&2 --- active on lower bound\\
+&3 --- active on upper bound\\
+&4 --- active free (unbounded) row\\
+&5 --- active equality constraint\\
+{\tt.val}&primal value of the linear form in the solution\\
+{\tt.dual}&dual value (reduced cost) of the linear form in the
+solution\\
+\end{tabular}
+
+\medskip
+
+Note that suffixes {\tt.status}, {\tt.val}, and {\tt.dual} can be used
+only below the solve statement.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Date and time functions}
+
+\noindent\hfil
+by Andrew Makhorin \verb|<mao@gnu.org>|
+
+\noindent\hfil
+and Heinrich Schuchardt \verb|<heinrich.schuchardt@gmx.de>|
+
+\subsection{Obtaining current calendar time}
+\label{gmtime}
+
+To obtain the current calendar time in MathProg there exists the
+function {\tt gmtime}. It has no arguments and returns the number of
+seconds elapsed since 00:00:00 on January 1, 1970, Coordinated
+Universal Time (UTC). For example:
+
+\medskip
+
+\verb|   param utc := gmtime();|
+
+\medskip
+
+MathProg has no function to convert UTC time returned by the function
+{\tt gmtime} to {\it local} calendar times. Thus, if you need to
+determine the current local calendar time, you have to add to the UTC
+time returned the time offset from UTC expressed in seconds. For
+example, the time in Berlin during the winter is one hour ahead of UTC
+that corresponds to the time offset +1 hour = +3600 secs, so the
+current winter calendar time in Berlin may be determined as follows:
+
+\medskip
+
+\verb|   param now := gmtime() + 3600;|
+
+\medskip
+
+\noindent Similarly, the summer time in Chicago (Central Daylight Time)
+is five hours behind UTC, so the corresponding current local calendar
+time may be determined as follows:
+
+\medskip
+
+\verb|   param now := gmtime() - 5 * 3600;|
+
+\medskip
+
+Note that the value returned by {\tt gmtime} is volatile, i.e. being
+called several times this function may return different values.
+
+\subsection{Converting character string to calendar time}
+\label{str2time}
+
+The function {\tt str2time(}{\it s}{\tt,} {\it f}{\tt)} converts a
+character string (timestamp) specified by its first argument {\it s},
+which must be a symbolic expression, to the calendar time suitable for
+arithmetic calculations. The conversion is controlled by the specified
+format string {\it f} (the second argument), which also must be a
+symbolic expression.
+
+The result of conversion returned by {\tt str2time} has the same
+meaning as values returned by the function {\tt gmtime} (see Subsection
+\ref{gmtime}, page \pageref{gmtime}). Note that {\tt str2time} does
+{\tt not} correct the calendar time returned for the local timezone,
+i.e. being applied to 00:00:00 on January 1, 1970 it always returns 0.
+
+For example, the model statements:
+
+\medskip
+
+\verb|   param s, symbolic, := "07/14/98 13:47";|
+
+\verb|   param t := str2time(s, "%m/%d/%y %H:%M");|
+
+\verb|   display t;|
+
+\medskip
+
+\noindent produce the following printout:
+
+\medskip
+
+\verb|   t = 900424020|
+
+\medskip
+
+\noindent where the calendar time printed corresponds to 13:47:00 on
+July 14, 1998.
+
+\newpage
+
+The format string passed to the function {\tt str2time} consists of
+conversion specifiers and ordinary characters. Each conversion
+specifier begins with a percent ({\tt\%}) character followed by a
+letter.
+
+The following conversion specifiers may be used in the format string:
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%b}&The abbreviated month name (case insensitive). At least three
+first letters of the month name must appear in the input string.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%d}&The day of the month as a decimal number (range 1 to 31).
+Leading zero is permitted, but not required.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%h}&The same as {\tt\%b}.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%H}&The hour as a decimal number, using a 24-hour clock (range 0
+to 23). Leading zero is permitted, but not required.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%m}&The month as a decimal number (range 1 to 12). Leading zero is
+permitted, but not required.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%M}&The minute as a decimal number (range 0 to 59). Leading zero
+is permitted, but not required.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%S}&The second as a decimal number (range 0 to 60). Leading zero
+is permitted, but not required.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%y}&The year without a century as a decimal number (range 0 to 99).
+Leading zero is permitted, but not required. Input values in the range
+0 to 68 are considered as the years 2000 to 2068 while the values 69 to
+99 as the years 1969 to 1999.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%z}&The offset from GMT in ISO 8601 format.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%\%}&A literal {\tt\%} character.\\
+\end{tabular}
+
+\medskip
+
+All other (ordinary) characters in the format string must have a
+matching character in the input string to be converted. Exceptions are
+spaces in the input string which can match zero or more space
+characters in the format string.
+
+If some date and/or time component(s) are missing in the format and,
+therefore, in the input string, the function {\tt str2time} uses their
+default values corresponding to 00:00:00 on January 1, 1970, that is,
+the default value of the year is 1970, the default value of the month
+is January, etc.
+
+The function {\tt str2time} is applicable to all calendar times in the
+range 00:00:00 on January 1, 0001 to 23:59:59 on December 31, 4000 of
+the Gregorian calendar.
+
+\subsection{Converting calendar time to character string}
+\label{time2str}
+
+The function {\tt time2str(}{\it t}{\tt,} {\it f}{\tt)} converts the
+calendar time specified by its first argument {\it t}, which must be a
+numeric expression, to a character string (symbolic value). The
+conversion is controlled by the specified format string {\it f} (the
+second argument), which must be a symbolic expression.
+
+The calendar time passed to {\tt time2str} has the same meaning as
+values returned by the function {\tt gmtime} (see Subsection
+\ref{gmtime}, page \pageref{gmtime}). Note that {\tt time2str} does
+{\it not} correct the specified calendar time for the local timezone,
+i.e. the calendar time 0 always corresponds to 00:00:00 on January 1,
+1970.
+
+For example, the model statements:
+
+\medskip
+
+\verb|   param s, symbolic, := time2str(gmtime(), "%FT%TZ");|
+
+\verb|   display s;|
+
+\medskip
+
+\noindent may produce the following printout:
+
+\medskip
+
+\verb|   s = '2008-12-04T00:23:45Z'|
+
+\medskip
+
+\noindent which is a timestamp in the ISO format.
+
+The format string passed to the function {\tt time2str} consists of
+conversion specifiers and ordinary characters. Each conversion
+specifier begins with a percent ({\tt\%}) character followed by a
+letter.
+
+The following conversion specifiers may be used in the format string:
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%a}&The abbreviated (2-character) weekday name.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%A}&The full weekday name.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%b}&The abbreviated (3-character) month name.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%B}&The full month name.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%C}&The century of the year, that is the greatest integer not
+greater than the year divided by 100.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%d}&The day of the month as a decimal number (range 01 to 31).\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%D}&The date using the format \verb|%m/%d/%y|.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%e}&The day of the month like with \verb|%d|, but padded with
+blank rather than zero.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%F}&The date using the format \verb|%Y-%m-%d|.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%g}&The year corresponding to the ISO week number, but without the
+century (range 00 to 99). This has the same format and value as
+\verb|%y|, except that if the ISO week number (see \verb|%V|) belongs
+to the previous or next year, that year is used instead.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%G}&The year corresponding to the ISO week number. This has the
+same format and value as \verb|%Y|, except that if the ISO week number
+(see \verb|%V|) belongs to the previous or next year, that year is used
+instead.
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%h}&The same as \verb|%b|.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%H}&The hour as a decimal number, using a 24-hour clock (range 00
+to 23).\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%I}&The hour as a decimal number, using a 12-hour clock (range 01
+to 12).\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%j}&The day of the year as a decimal number (range 001 to 366).\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%k}&The hour as a decimal number, using a 24-hour clock like
+\verb|%H|, but padded with blank rather than zero.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%l}&The hour as a decimal number, using a 12-hour clock like
+\verb|%I|, but padded with blank rather than zero.
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%m}&The month as a decimal number (range 01 to 12).\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%M}&The minute as a decimal number (range 00 to 59).\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%p}&Either {\tt AM} or {\tt PM}, according to the given time value.
+Midnight is treated as {\tt AM} and noon as {\tt PM}.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%P}&Either {\tt am} or {\tt pm}, according to the given time value.
+Midnight is treated as {\tt am} and noon as {\tt pm}.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%R}&The hour and minute in decimal numbers using the format
+\verb|%H:%M|.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%S}&The second as a decimal number (range 00 to 59).\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%T}&The time of day in decimal numbers using the format
+\verb|%H:%M:%S|.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%u}&The day of the week as a decimal number (range 1 to 7), Monday
+being 1.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%U}&The week number of the current year as a decimal number (range
+00 to 53), starting with the first Sunday as the first day of the first
+week. Days preceding the first Sunday in the year are considered to be
+in week 00.
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%V}&The ISO week number as a decimal number (range 01 to 53). ISO
+weeks start with Monday and end with Sunday. Week 01 of a year is the
+first week which has the majority of its days in that year; this is
+equivalent to the week containing January 4. Week 01 of a year can
+contain days from the previous year. The week before week 01 of a year
+is the last week (52 or 53) of the previous year even if it contains
+days from the new year. In other word, if 1 January is Monday, Tuesday,
+Wednesday or Thursday, it is in week 01; if 1 January is Friday,
+Saturday or Sunday, it is in week 52 or 53 of the previous year.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%w}&The day of the week as a decimal number (range 0 to 6), Sunday
+being 0.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%W}&The week number of the current year as a decimal number (range
+00 to 53), starting with the first Monday as the first day of the first
+week. Days preceding the first Monday in the year are considered to be
+in week 00.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%y}&The year without a century as a decimal number (range 00 to
+99), that is the year modulo 100.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%Y}&The year as a decimal number, using the Gregorian calendar.\\
+\end{tabular}
+
+\medskip
+
+\begin{tabular}{@{}p{20pt}p{298pt}@{}}
+{\tt\%\%}&A literal \verb|%| character.\\
+\end{tabular}
+
+\medskip
+
+All other (ordinary) characters in the format string are simply copied
+to the resultant string.
+
+The first argument (calendar time) passed to the function {\tt time2str}
+must be in the range from $-62135596800$ to $+64092211199$ that
+corresponds to the period from 00:00:00 on January 1, 0001 to 23:59:59
+on December 31, 4000 of the Gregorian calendar.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Table drivers}
+\label{drivers}
+
+\noindent\hfil
+by Andrew Makhorin \verb|<mao@gnu.org>|
+
+\noindent\hfil
+and Heinrich Schuchardt \verb|<heinrich.schuchardt@gmx.de>|
+
+\bigskip\bigskip
+
+The {\it table driver} is a program module which provides transmitting
+data between MathProg model objects and data tables.
+
+Currently the GLPK package has four table drivers:
+
+\setlength{\leftmargini}{2.5em}
+
+\begin{itemize}
+\item built-in CSV table driver;
+\item built-in xBASE table driver;
+\item ODBC table driver;
+\item MySQL table driver.
+\end{itemize}
+
+\subsection{CSV table driver}
+
+The CSV table driver assumes that the data table is represented in the
+form of a plain text file in the CSV (comma-separated values) file
+format as described below.
+
+To choose the CSV table driver its name in the table statement should
+be specified as \verb|"CSV"|, and the only argument should specify the
+name of a plain text file containing the table. For example:
+
+\medskip
+
+\verb|   table data IN "CSV" "data.csv": ... ;|
+
+\medskip
+
+The filename suffix may be arbitrary, however, it is recommended to use
+the suffix `\verb|.csv|'.
+
+On reading input tables the CSV table driver provides an implicit field
+named \verb|RECNO|, which contains the current record number. This
+field can be specified in the input table statement as if there were
+the actual field having the name \verb|RECNO| in the CSV file. For
+example:
+
+\medskip
+
+\verb|   table list IN "CSV" "list.csv": num <- [RECNO], ... ;|
+
+\subsubsection*{CSV format\footnote{This material is based on the RFC
+document 4180.}}
+
+The CSV (comma-separated values) format is a plain text file format
+defined as follows.
+
+1. Each record is located on a separate line, delimited by a line
+break. For example:
+
+\medskip
+
+\verb|   aaa,bbb,ccc\n|
+
+\verb|   xxx,yyy,zzz\n|
+
+\medskip
+
+\noindent
+where \verb|\n| means the control character \verb|LF| ({\tt 0x0A}).
+
+\newpage
+
+2. The last record in the file may or may not have an ending line
+break. For example:
+
+\medskip
+
+\verb|   aaa,bbb,ccc\n|
+
+\verb|   xxx,yyy,zzz|
+
+\medskip
+
+3. There should be a header line appearing as the first line of the
+file in the same format as normal record lines. This header should
+contain names corresponding to the fields in the file. The number of
+field names in the header line should be the same as the number of
+fields in the records of the file. For example:
+
+\medskip
+
+\verb|   name1,name2,name3\n|
+
+\verb|   aaa,bbb,ccc\n|
+
+\verb|   xxx,yyy,zzz\n|
+
+\medskip
+
+4. Within the header and each record there may be one or more fields
+separated by commas. Each line should contain the same number of fields
+throughout the file. Spaces are considered as part of a field and
+therefore not ignored. The last field in the record should not be
+followed by a comma. For example:
+
+\medskip
+
+\verb|   aaa,bbb,ccc\n|
+
+\medskip
+
+5. Fields may or may not be enclosed in double quotes. For example:
+
+\medskip
+
+\verb|   "aaa","bbb","ccc"\n|
+
+\verb|   zzz,yyy,xxx\n|
+
+\medskip
+
+6. If a field is enclosed in double quotes, each double quote which is
+part of the field should be coded twice. For example:
+
+\medskip
+
+\verb|   "aaa","b""bb","ccc"\n|
+
+\medskip
+
+\noindent{\bf Example}
+
+\begin{verbatim}
+FROM,TO,DISTANCE,COST
+Seattle,New-York,2.5,0.12
+Seattle,Chicago,1.7,0.08
+Seattle,Topeka,1.8,0.09
+San-Diego,New-York,2.5,0.15
+San-Diego,Chicago,1.8,0.10
+San-Diego,Topeka,1.4,0.07
+\end{verbatim}
+
+\subsection{xBASE table driver}
+
+The xBASE table driver assumes that the data table is stored in the
+.dbf file format.
+
+To choose the xBASE table driver its name in the table statement should
+be specified as \verb|"xBASE"|, and the first argument should specify
+the name of a .dbf file containing the table. For the output table there
+should be the second argument defining the table format in the form
+\verb|"FF...F"|, where \verb|F| is either {\tt C({\it n})},
+which specifies a character field of length $n$, or
+{\tt N({\it n}{\rm [},{\it p}{\rm ]})}, which specifies a numeric field
+of length $n$ and precision $p$ (by default $p$ is 0).
+
+The following is a simple example which illustrates creating and
+reading a .dbf file:
+
+\begin{verbatim}
+table tab1{i in 1..10} OUT "xBASE" "foo.dbf"
+   "N(5)N(10,4)C(1)C(10)": 2*i+1 ~ B, Uniform(-20,+20) ~ A,
+   "?" ~ FOO, "[" & i & "]" ~ C;
+set S, dimen 4;
+table tab2 IN "xBASE" "foo.dbf": S <- [B, C, RECNO, A];
+display S;
+end;
+\end{verbatim}
+
+\subsection{ODBC table driver}
+
+The ODBC table driver allows connecting to SQL databases using an
+implementation of the ODBC interface based on the Call Level Interface
+(CLI).\footnote{The corresponding software standard is defined in
+ISO/IEC 9075-3:2003.}
+
+\paragraph{Debian GNU/Linux.}
+Under Debian GNU/Linux the ODBC table driver uses the iODBC
+package,\footnote{See {\tt<http://www.iodbc.org/>}.} which should be
+installed before building the GLPK package. The installation can be
+effected with the following command:
+
+\begin{verbatim}
+sudo apt-get install libiodbc2-dev
+\end{verbatim}
+
+Note that on configuring the GLPK package to enable using the iODBC
+library the option `\verb|--enable-odbc|' should be passed to the
+configure script.
+
+The individual databases must be entered for systemwide usage in
+\linebreak \verb|/etc/odbc.ini| and \verb|/etc/odbcinst.ini|. Database
+connections to be used by a single user are specified by files in the
+home directory (\verb|.odbc.ini| and \verb|.odbcinst.ini|).
+
+\paragraph{Microsoft Windows.}
+Under Microsoft Windows the ODBC table driver uses the Microsoft ODBC
+library. To enable this feature the symbol:
+
+\begin{verbatim}
+#define ODBC_DLNAME "odbc32.dll"
+\end{verbatim}
+
+\noindent
+should be defined in the GLPK configuration file `\verb|config.h|'.
+
+Data sources can be created via the Administrative Tools from the
+Control Panel.
+
+\bigskip
+
+To choose the ODBC table driver its name in the table statement should
+be specified as \verb|'ODBC'| or \verb|'iODBC'|.
+
+The argument list is specified as follows.
+
+The first argument is the connection string passed to the ODBC library,
+for example:
+
+\verb|'DSN=glpk;UID=user;PWD=password'|, or
+
+\verb|'DRIVER=MySQL;DATABASE=glpkdb;UID=user;PWD=password'|.
+
+Different parts of the string are separated by semicolons. Each part
+consists of a pair {\it fieldname} and {\it value} separated by the
+equal sign. Allowable fieldnames depend on the ODBC library. Typically
+the following fieldnames are allowed:
+
+\verb|DATABASE | database;
+
+\verb|DRIVER   | ODBC driver;
+
+\verb|DSN      | name of a data source;
+
+\verb|FILEDSN  | name of a file data source;
+
+\verb|PWD      | user password;
+
+\verb|SERVER   | database;
+
+\verb|UID      | user name.
+
+The second argument and all following are considered to be SQL
+statements
+
+SQL statements may be spread over multiple arguments.  If the last
+character of an argument is a semicolon this indicates the end of
+a SQL statement.
+
+The arguments of a SQL statement are concatenated separated by space.
+The eventual trailing semicolon will be removed.
+
+All but the last SQL statement will be executed directly.
+
+For IN-table the last SQL statement can be a SELECT command starting
+with the capitalized letters \verb|'SELECT '|. If the string does not
+start with \verb|'SELECT '| it is considered to be a table name and a
+SELECT statement is automatically generated.
+
+For OUT-table the last SQL statement can contain one or multiple
+question marks. If it contains a question mark it is considered a
+template for the write routine. Otherwise the string is considered a
+table name and an INSERT template is automatically generated.
+
+The writing routine uses the template with the question marks and
+replaces the first question mark by the first output parameter, the
+second question mark by the second output parameter and so forth. Then
+the SQL command is issued.
+
+The following is an example of the output table statement:
+
+\begin{small}
+\begin{verbatim}
+table ta { l in LOCATIONS } OUT
+   'ODBC'
+   'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
+   'DROP TABLE IF EXISTS result;'
+   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
+   'INSERT INTO result 'VALUES ( 4, ?, ? )' :
+   l ~ LOC, quantity[l] ~ QUAN;
+\end{verbatim}
+\end{small}
+
+\noindent
+Alternatively it could be written as follows:
+
+\begin{small}
+\begin{verbatim}
+table ta { l in LOCATIONS } OUT
+   'ODBC'
+   'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
+   'DROP TABLE IF EXISTS result;'
+   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
+   'result' :
+   l ~ LOC, quantity[l] ~ QUAN, 4 ~ ID;
+\end{verbatim}
+\end{small}
+
+Using templates with `\verb|?|' supports not only INSERT, but also
+UPDATE, DELETE, etc. For example:
+
+\begin{small}
+\begin{verbatim}
+table ta { l in LOCATIONS } OUT
+   'ODBC'
+   'DSN=glpkdb;UID=glpkuser;PWD=glpkpassword'
+   'UPDATE result SET DATE = ' & date & ' WHERE ID = 4;'
+   'UPDATE result SET QUAN = ? WHERE LOC = ? AND ID = 4' :
+   quantity[l], l;
+\end{verbatim}
+\end{small}
+
+\subsection{MySQL table driver}
+
+The MySQL table driver allows connecting to MySQL databases.
+
+\paragraph{Debian GNU/Linux.}
+Under Debian GNU/Linux the MySQL table\linebreak driver uses the MySQL
+package,\footnote{For download development files see
+{\tt<http://dev.mysql.com/downloads/mysql/>}.} which should be installed
+before building the GLPK package. The installation can be effected with
+the following command:
+
+\begin{verbatim}
+sudo apt-get install libmysqlclient15-dev
+\end{verbatim}
+
+Note that on configuring the GLPK package to enable using the MySQL
+library the option `\verb|--enable-mysql|' should be passed to the
+configure script.
+
+\paragraph{Microsoft Windows.}
+Under Microsoft Windows the MySQL table driver also uses the MySQL
+library. To enable this feature the symbol:
+
+\begin{verbatim}
+#define MYSQL_DLNAME "libmysql.dll"
+\end{verbatim}
+
+\noindent
+should be defined in the GLPK configuration file `\verb|config.h|'.
+
+\bigskip
+
+To choose the MySQL table driver its name in the table statement should
+be specified as \verb|'MySQL'|.
+
+The argument list is specified as follows.
+
+The first argument specifies how to connect the data base in the DSN
+style, for example:
+
+\verb|'Database=glpk;UID=glpk;PWD=gnu'|.
+
+Different parts of the string are separated by semicolons. Each part
+consists of a pair {\it fieldname} and {\it value} separated by the
+equal sign. The following fieldnames are allowed:
+
+\verb|Server   | server running the database (defaulting to localhost);
+
+\verb|Database | name of the database;
+
+\verb|UID      | user name;
+
+\verb|PWD      | user password;
+
+\verb|Port     | port used by the server (defaulting to 3306).
+
+The second argument and all following are considered to be SQL
+statements
+
+SQL statements may be spread over multiple arguments.  If the last
+character of an argument is a semicolon this indicates the end of
+a SQL statement.
+
+The arguments of a SQL statement are concatenated separated by space.
+The eventual trailing semicolon will be removed.
+
+All but the last SQL statement will be executed directly.
+
+For IN-table the last SQL statement can be a SELECT command starting
+with the capitalized letters \verb|'SELECT '|. If the string does not
+start with \verb|'SELECT '| it is considered to be a table name and a
+SELECT statement is automatically generated.
+
+For OUT-table the last SQL statement can contain one or multiple
+question marks. If it contains a question mark it is considered a
+template for the write routine. Otherwise the string is considered a
+table name and an INSERT template is automatically generated.
+
+The writing routine uses the template with the question marks and
+replaces the first question mark by the first output parameter, the
+second question mark by the second output parameter and so forth. Then
+the SQL command is issued.
+
+The following is an example of the output table statement:
+
+\begin{small}
+\begin{verbatim}
+table ta { l in LOCATIONS } OUT
+   'MySQL'
+   'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
+   'DROP TABLE IF EXISTS result;'
+   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
+   'INSERT INTO result VALUES ( 4, ?, ? )' :
+   l ~ LOC, quantity[l] ~ QUAN;
+\end{verbatim}
+\end{small}
+
+\noindent
+Alternatively it could be written as follows:
+
+\begin{small}
+\begin{verbatim}
+table ta { l in LOCATIONS } OUT
+   'MySQL'
+   'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
+   'DROP TABLE IF EXISTS result;'
+   'CREATE TABLE result ( ID INT, LOC VARCHAR(255), QUAN DOUBLE );'
+   'result' :
+   l ~ LOC, quantity[l] ~ QUAN, 4 ~ ID;
+\end{verbatim}
+\end{small}
+
+Using templates with `\verb|?|' supports not only INSERT, but also
+UPDATE, DELETE, etc. For example:
+
+\begin{small}
+\begin{verbatim}
+table ta { l in LOCATIONS } OUT
+   'MySQL'
+   'Database=glpkdb;UID=glpkuser;PWD=glpkpassword'
+   'UPDATE result SET DATE = ' & date & ' WHERE ID = 4;'
+   'UPDATE result SET QUAN = ? WHERE LOC = ? AND ID = 4' :
+   quantity[l], l;
+\end{verbatim}
+\end{small}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Solving models with glpsol}
+
+The GLPK package\footnote{{\tt http://www.gnu.org/software/glpk/}}
+includes the program {\tt glpsol}, which is a stand-alone LP/MIP solver.
+This program can be launched from the command line or from the shell to
+solve models written in the GNU MathProg modeling language.
+
+In order to tell the solver that the input file contains a model
+description, you need to specify the option \verb|--model| in the
+command line. For example:
+
+\medskip
+
+\verb|   glpsol --model foo.mod|
+
+\medskip
+
+Sometimes it is necessary to use the data section placed in a separate
+file, in which case you may use the following command:
+
+\medskip
+
+\verb|   glpsol --model foo.mod --data foo.dat|
+
+\medskip
+
+\noindent Note that if the model file also contains the data section,
+that section is ignored.
+
+If the model description contains some display and/or printf statements,
+by default the output is sent to the terminal. In order to redirect the
+output to a file you may use the following command:
+
+\medskip
+
+\verb|   glpsol --model foo.mod --display foo.out|
+
+\medskip
+
+If you need to look at the problem, which has been generated by the
+model translator, you may use the option \verb|--wlp| as follows:
+
+\medskip
+
+\verb|   glpsol --model foo.mod --wlp foo.lp|
+
+\medskip
+
+\noindent in which case the problem data is written to file
+\verb|foo.lp| in CPLEX LP format suitable for visual analysis.
+
+Sometimes it is needed merely to check the model description not
+solving the generated problem instance. In this case you may specify
+the option \verb|--check|, for example:
+
+\medskip
+
+\verb|   glpsol --check --model foo.mod --wlp foo.lp|
+
+\medskip
+
+In order to write a numeric solution obtained by the solver you may use
+the following command:
+
+\medskip
+
+\verb|   glpsol --model foo.mod --output foo.sol|
+
+\medskip
+
+\noindent in which case the solution is written to file \verb|foo.sol|
+in a plain text format.
+
+The complete list of the \verb|glpsol| options can be found in the
+reference manual included in the GLPK distribution.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Example model description}
+
+\subsection{Model description written in MathProg}
+
+Below here is a complete example of the model description written in
+the GNU MathProg modeling language.
+
+\begin{small}
+\begin{verbatim}
+# A TRANSPORTATION PROBLEM
+#
+# This problem finds a least cost shipping schedule that meets
+# requirements at markets and supplies at factories.
+#
+#  References:
+#              Dantzig G B, "Linear Programming and Extensions."
+#              Princeton University Press, Princeton, New Jersey, 1963,
+#              Chapter 3-3.
+
+set I;
+/* canning plants */
+
+set J;
+/* markets */
+
+param a{i in I};
+/* capacity of plant i in cases */
+
+param b{j in J};
+/* demand at market j in cases */
+
+param d{i in I, j in J};
+/* distance in thousands of miles */
+
+param f;
+/* freight in dollars per case per thousand miles */
+
+param c{i in I, j in J} := f * d[i,j] / 1000;
+/* transport cost in thousands of dollars per case */
+
+var x{i in I, j in J} >= 0;
+/* shipment quantities in cases */
+
+minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
+/* total transportation costs in thousands of dollars */
+
+s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
+/* observe supply limit at plant i */
+
+s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
+/* satisfy demand at market j */
+
+data;
+
+set I := Seattle San-Diego;
+
+set J := New-York Chicago Topeka;
+
+param a := Seattle     350
+           San-Diego   600;
+
+param b := New-York    325
+           Chicago     300
+           Topeka      275;
+
+param d :              New-York   Chicago   Topeka :=
+           Seattle     2.5        1.7       1.8
+           San-Diego   2.5        1.8       1.4  ;
+
+param f := 90;
+
+end;
+\end{verbatim}
+\end{small}
+
+\subsection{Generated LP problem instance}
+
+Below here is the result of the translation of the example model
+produced by the solver \verb|glpsol| and written in CPLEX LP format
+with the option \verb|--wlp|.
+
+\begin{small}
+\begin{verbatim}
+\* Problem: transp *\
+
+Minimize
+ cost: + 0.225 x(Seattle,New~York) + 0.153 x(Seattle,Chicago)
+ + 0.162 x(Seattle,Topeka) + 0.225 x(San~Diego,New~York)
+ + 0.162 x(San~Diego,Chicago) + 0.126 x(San~Diego,Topeka)
+
+Subject To
+ supply(Seattle): + x(Seattle,New~York) + x(Seattle,Chicago)
+ + x(Seattle,Topeka) <= 350
+ supply(San~Diego): + x(San~Diego,New~York) + x(San~Diego,Chicago)
+ + x(San~Diego,Topeka) <= 600
+ demand(New~York): + x(Seattle,New~York) + x(San~Diego,New~York) >= 325
+ demand(Chicago): + x(Seattle,Chicago) + x(San~Diego,Chicago) >= 300
+ demand(Topeka): + x(Seattle,Topeka) + x(San~Diego,Topeka) >= 275
+
+End
+\end{verbatim}
+\end{small}
+
+\subsection{Optimal LP solution}
+
+Below here is the optimal solution of the generated LP problem instance
+found by the solver \verb|glpsol| and written in plain text format
+with the option \verb|--output|.
+
+\newpage
+
+\begin{small}
+\begin{verbatim}
+Problem:    transp
+Rows:       6
+Columns:    6
+Non-zeros:  18
+Status:     OPTIMAL
+Objective:  cost = 153.675 (MINimum)
+
+No.   Row name   St   Activity    Lower bound  Upper bound   Marginal
+--- ------------ -- ------------ ------------ ------------ ------------
+  1 cost         B       153.675
+  2 supply[Seattle]
+                 B           300                       350
+  3 supply[San-Diego]
+                 NU          600                       600        < eps
+  4 demand[New-York]
+                 NL          325          325                     0.225
+  5 demand[Chicago]
+                 NL          300          300                     0.153
+  6 demand[Topeka]
+                 NL          275          275                     0.126
+
+No. Column name  St   Activity    Lower bound  Upper bound   Marginal
+--- ------------ -- ------------ ------------ ------------ ------------
+  1 x[Seattle,New-York]
+                 B             0            0
+  2 x[Seattle,Chicago]
+                 B           300            0
+  3 x[Seattle,Topeka]
+                 NL            0            0                     0.036
+  4 x[San-Diego,New-York]
+                 B           325            0
+  5 x[San-Diego,Chicago]
+                 NL            0            0                     0.009
+  6 x[San-Diego,Topeka]
+                 B           275            0
+
+End of output
+\end{verbatim}
+\end{small}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\setcounter{secnumdepth}{-1}
+
+\section{Acknowledgment}
+
+The authors would like to thank the following people, who kindly read,
+commented, and corrected the draft of this document:
+
+\medskip
+
+\noindent Juan Carlos Borras \verb|<borras@cs.helsinki.fi>|
+
+\medskip
+
+\noindent Harley Mackenzie \verb|<hjm@bigpond.com>|
+
+\medskip
+
+\noindent Robbie Morrison \verb|<robbie@actrix.co.nz>|
+
+\end{document}
Index: deps/glpk/doc/graphs.tex
===================================================================
--- deps/glpk/doc/graphs.tex	(revision 9)
+++ deps/glpk/doc/graphs.tex	(revision 9)
@@ -0,0 +1,3935 @@
+%* graphs.tex *%
+
+%***********************************************************************
+%  This code is part of GLPK (GNU Linear Programming Kit).
+%
+%  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+%  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+%  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+%  E-mail: <mao@gnu.org>.
+%
+%  GLPK is free software: you can redistribute it and/or modify it
+%  under the terms of the GNU General Public License as published by
+%  the Free Software Foundation, either version 3 of the License, or
+%  (at your option) any later version.
+%
+%  GLPK is distributed in the hope that it will be useful, but WITHOUT
+%  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+%  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+%  License for more details.
+%
+%  You should have received a copy of the GNU General Public License
+%  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+%***********************************************************************
+
+\documentclass[11pt]{report}
+\usepackage{amssymb}
+\usepackage[dvipdfm,linktocpage,colorlinks,linkcolor=blue,
+urlcolor=blue]{hyperref}
+\usepackage[all]{xy}
+
+\renewcommand\contentsname{\sf\bfseries Contents}
+\renewcommand\chaptername{\sf\bfseries Chapter}
+\renewcommand\appendixname{\sf\bfseries Appendix}
+
+\begin{document}
+
+\thispagestyle{empty}
+
+\begin{center}
+
+\vspace*{1in}
+
+\begin{huge}
+\sf\bfseries GNU Linear Programming Kit
+\end{huge}
+
+\vspace{0.5in}
+
+\begin{LARGE}
+\sf Graph and Network Routines
+\end{LARGE}
+
+\vspace{0.5in}
+
+\begin{LARGE}
+\sf for GLPK Version 4.45
+\end{LARGE}
+
+\vspace{0.5in}
+\begin{Large}
+\sf (DRAFT, December 2010)
+\end{Large}
+\end{center}
+
+\newpage
+
+\vspace*{1in}
+
+\vfill
+
+\noindent
+The GLPK package is part of the GNU Project released under the aegis of
+GNU.
+
+\medskip \noindent
+Copyright \copyright{} 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+2008, 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+
+\medskip \noindent
+Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+\medskip \noindent
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+\medskip \noindent
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+entire resulting derived work is distributed under the terms of
+a permission notice identical to this one.
+
+\medskip \noindent
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+
+\tableofcontents
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\chapter{Basic Graph API Routines}
+
+\section{Graph program object}
+
+In GLPK the base program object used to represent graphs and networks
+is a directed graph (digraph).
+
+Formally, {\it digraph} (or simply, {\it graph}) is a pair $G=(V,A)$,
+where $V$ is a set of {\it vertices}, and $A$ is a set
+{\it arcs}.\footnote{$A$ may be a multiset.} Each arc $a\in A$ is an
+ordered pair of vertices $a=(x,y)$, where $x\in V$ is called {\it tail
+vertex} of arc $a$, and $y\in V$ is called its {\it head vertex}.
+
+Representation of a graph in the program includes three structs defined
+by typedef in the header \verb|glpk.h|:
+
+\medskip
+
+$\bullet$ \verb|glp_graph|, which represents the graph in a whole,
+
+$\bullet$ \verb|glp_vertex|, which represents a vertex of the graph, and
+
+$\bullet$ \verb|glp_arc|, which represents an arc of the graph.
+
+\medskip
+
+All these three structs are ``semi-opaque'', i.e. the application
+program can directly access their fields through pointers, however,
+changing the fields directly is not allowed---all changes should be
+performed only with appropriate GLPK API routines.
+
+\newpage
+
+\newenvironment{comment}
+{\addtolength{\leftskip}{17pt}\noindent}
+{\par\addtolength{\leftskip}{-17pt}}
+
+\noindent
+{\bf glp\_graph.} The struct \verb|glp_graph| has the following
+fields available to the application program:
+
+\medskip
+
+\noindent
+\verb|char *name;|
+
+\begin{comment}Symbolic name assigned to the graph. It is a pointer to
+a null terminated character string of length from 1 to 255 characters.
+If no name is assigned to the graph, this field contains \verb|NULL|.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|int nv;|
+
+\begin{comment}The number of vertices in the graph, $nv\geq 0$.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|int na;|
+
+\begin{comment}The number of arcs in the graph, $na\geq 0$.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|glp_vertex **v;|
+
+\begin{comment}Pointer to an array containing the list of vertices.
+Element $v[0]$ is not used. Element $v[i]$, $1\leq i\leq nv$, is a
+pointer to $i$-th vertex of the graph. Note that on adding new vertices
+to the graph the field $v$ may be altered due to reallocation. However,
+pointers $v[i]$ are not changed while corresponding vertices exist in
+the graph.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|int v_size;|
+
+\begin{comment}Size of vertex data blocks, in bytes,
+$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
+\verb|glp_vertex|.)
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|int a_size;|
+
+\begin{comment}Size of arc data blocks, in bytes,
+$0\leq v\_size\leq 256$. (See also the field \verb|data| in the struct
+\verb|glp_arc|.)
+\end{comment}
+
+\bigskip
+
+\noindent
+{\bf glp\_vertex.} The struct \verb|glp_vertex| has the following
+fields available to the application program:
+
+\medskip
+
+\noindent
+\verb|int i;|
+
+\begin{comment}Ordinal number of the vertex, $1\leq i\leq nv$. Note
+that element $v[i]$ in the struct \verb|glp_graph| points to the vertex,
+whose ordinal number is $i$.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|char *name;|
+
+\begin{comment}Symbolic name assigned to the vertex. It is a pointer to
+a null terminated character string of length from 1 to 255 characters.
+If no name is assigned to the vertex, this field contains \verb|NULL|.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|void *data;|
+
+\begin{comment}Pointer to a data block associated with the vertex. This
+data block is automatically allocated on creating a new vertex and freed
+on deleting the vertex. If $v\_size=0$, the block is not allocated, and
+this field contains \verb|NULL|.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|void *temp;|
+
+\begin{comment}Working pointer, which may be used freely for any
+purposes. The application program can change this field directly.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|glp_arc *in;|
+
+\begin{comment}Pointer to the (unordered) list of incoming arcs. If the
+vertex has no incoming arcs, this field contains \verb|NULL|.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|glp_arc *out;|
+
+\begin{comment}Pointer to the (unordered) list of outgoing arcs. If the
+vertex has no outgoing arcs, this field contains \verb|NULL|.
+\end{comment}
+
+\bigskip
+
+\noindent
+{\bf glp\_arc.} The struct \verb|glp_arc| has the following fields
+available to the application program:
+
+\medskip
+
+\noindent
+\verb|glp_vertex *tail;|
+
+\begin{comment}Pointer to a vertex, which is tail endpoint of the arc.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|glp_vertex *head;|
+
+\begin{comment}Pointer to a vertex, which is head endpoint of the arc.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|void *data;|
+
+\begin{comment}Pointer to a data block associated with the arc. This
+data block is automatically allocated on creating a new arc and freed on
+deleting the arc. If $v\_size=0$, the block is not allocated, and this
+field contains \verb|NULL|.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|void *temp;|
+
+\begin{comment}Working pointer, which may be used freely for any
+purposes. The application program can change this field directly.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|glp_arc *t_next;|
+
+\begin{comment}Pointer to another arc, which has the same tail endpoint
+as this one. \verb|NULL| in this field indicates the end of the list of
+outgoing arcs.
+\end{comment}
+
+\medskip
+
+\noindent
+\verb|glp_arc *h_next;|
+
+\begin{comment}Pointer to another arc, which has the same head endpoint
+as this one. \verb|NULL| in this field indicates the end of the list of
+incoming arcs.
+\end{comment}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Graph creating and modifying routines}
+
+\subsection{glp\_create\_graph---create graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+glp_graph *glp_create_graph(int v_size, int a_size);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_create_graph| creates a new graph, which
+initially is\linebreak empty, i.e. has no vertices and arcs.
+
+The parameter \verb|v_size| specifies the size of vertex data blocks,
+in bytes, $0\leq v\_size\leq 256$.
+
+The parameter \verb|a_size| specifies the size of arc data blocks, in
+bytes, $0\leq a\_size\leq 256$.
+
+\subsubsection*{Returns}
+
+The routine returns a pointer to the graph created.
+
+\subsection{glp\_set\_graph\_name---assign (change) graph name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_graph_name(glp_graph *G, const char *name);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_graph_name| assigns a symbolic name specified
+by the character string \verb|name| (1 to 255 chars) to the graph.
+
+If the parameter \verb|name| is \verb|NULL| or an empty string, the
+routine erases the existing symbolic name of the graph.
+
+\newpage
+
+\subsection{glp\_add\_vertices---add new vertices to graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_add_vertices(glp_graph *G, int nadd);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_add_vertices| adds \verb|nadd| vertices to the
+specified graph. New vertices are always added to the end of the vertex
+list, so ordinal numbers of existing vertices remain unchanged. Note
+that this operation may change the field \verb|v| in the struct
+\verb|glp_graph| (pointer to the vertex array) due to reallocation.
+
+Being added each new vertex is isolated, i.e. has no incident arcs.
+
+If the size of vertex data blocks specified on creating the graph is
+non-zero, the routine also allocates a memory block of that size for
+each new vertex added, fills it by binary zeros, and stores a pointer to
+it in the field \verb|data| of the struct \verb|glp_vertex|. Otherwise,
+if the block size is zero, the field \verb|data| is set to \verb|NULL|.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_add_vertices| returns the ordinal number of the
+first new vertex added to the graph.
+
+\subsection{glp\_set\_vertex\_name---assign (change) vertex name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_set_vertex_name(glp_graph *G, int i, const char *name);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_set_vertex_name| assigns a given symbolic name
+(1 up to 255 characters) to \verb|i|-th vertex of the specified graph.
+
+If the parameter \verb|name| is \verb|NULL| or empty string, the
+routine erases an existing name of \verb|i|-th vertex.
+
+\newpage
+
+\subsection{glp\_add\_arc---add new arc to graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+glp_arc *glp_add_arc(glp_graph *G, int i, int j);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_add_arc| adds one new arc to the specified graph.
+
+The parameters \verb|i| and \verb|j| specify the ordinal numbers of,
+resp., tail and head endpoints (vertices) of the arc. Note that
+self-loops and multiple arcs are allowed.
+
+If the size of arc data blocks specified on creating the graph is
+non-zero, the routine also allocates a memory block of that size, fills
+it by binary zeros, and stores a pointer to it in the field \verb|data|
+of the struct \verb|glp_arc|. Otherwise, if the block size is zero, the
+field \verb|data| is set to \verb|NULL|.
+
+\subsection{glp\_del\_vertices---delete vertices from graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_del_vertices| deletes vertices along with all
+incident arcs from the specified graph. Ordinal numbers of vertices to
+be deleted should be placed in locations \verb|num[1]|, \dots,
+\verb|num[ndel]|, \verb|ndel| $>0$.
+
+Note that deleting vertices involves changing ordinal numbers of other
+vertices remaining in the graph. New ordinal numbers of the remaining
+vertices are assigned under the assumption that the original order of
+vertices is not changed.
+
+\subsection{glp\_del\_arc---delete arc from graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_del_arc(glp_graph *G, glp_arc *a);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_del_arc| deletes an arc from the specified graph.
+The arc to be deleted must exist.
+
+\subsection{glp\_erase\_graph---erase graph content}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_erase_graph(glp_graph *G, int v_size, int a_size);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_erase_graph| erases the content of the specified
+graph. The effect of this operation is the same as if the graph would be
+deleted with the routine \verb|glp_delete_graph| and then created anew
+with the routine \verb|glp_create_graph|, with exception that the handle
+(pointer) to the graph remains valid.
+
+The parameters \verb|v_size| and \verb|a_size| have the same meaning as
+for the routine \verb|glp_create_graph|.
+
+\subsection{glp\_delete\_graph---delete graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_delete_graph(glp_graph *G);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_delete_graph| deletes the specified graph and
+frees all the memory allocated to this program object.
+
+\newpage
+
+\section{Graph searching routines}
+
+\subsection{glp\_create\_v\_index---create vertex name index}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_create_v_index(glp_graph *G);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_create_v_index| creates the name index for the
+specified graph. The name index is an auxiliary data structure, which
+is intended to quickly (i.e. for logarithmic time) find vertices by
+their names.
+
+This routine can be called at any time. If the name index already
+exists, the routine does nothing.
+
+\subsection{glp\_find\_vertex---find vertex by its name}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_find_vertex(glp_graph *G, const char *name);
+\end{verbatim}
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_find_vertex| returns the ordinal number of
+a vertex, which is assigned (by the routine \verb|glp_set_vertex_name|)
+the specified symbolic \verb|name|. If no such vertex exists, the
+routine returns 0.
+
+\subsection{glp\_delete\_v\_index---delete vertex name index}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_delete_v_index(glp_graph *G);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_delete_v_index| deletes the name index previously
+created by the routine \verb|glp_create_v_index| and frees the memory
+allocated to this auxiliary data structure.
+
+This routine can be called at any time. If the name index does not
+exist, the routine does nothing.
+
+\newpage
+
+\section{Graph reading/writing routines}
+
+\subsection{glp\_read\_graph---read graph from plain text file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_graph(glp_graph *G, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_graph| reads a graph from a plain text file,
+whose name is specified by the parameter \verb|fname|. Note that before
+reading data the current content of the graph object is completely
+erased with the routine \verb|glp_erase_graph|.
+
+For the file format see description of the routine
+\verb|glp_write_graph|.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise
+it prints an error message and returns non-zero.
+
+\subsection{glp\_write\_graph---write graph to plain text file}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_graph(glp_graph *G, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_graph| writes the graph to a plain text
+file, whose name is specified by the parameter \verb|fname|.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise
+it prints an error message and returns non-zero.
+
+\subsubsection*{File format}
+
+The file created by the routine \verb|glp_write_graph| is a plain text
+file, which contains the following information:
+
+\begin{verbatim}
+   nv na
+   i[1] j[1]
+   i[2] j[2]
+   . . .
+   i[na] j[na]
+\end{verbatim}
+
+\noindent
+where:
+
+\noindent
+\verb|nv| is the number of vertices (nodes);
+
+\noindent
+\verb|na| is the number of arcs;
+
+\noindent
+\verb|i[k]|, $k=1,\dots,na$, is the index of tail vertex of arc $k$;
+
+\noindent
+\verb|j[k]|, $k=1,\dots,na$, is the index of head vertex of arc $k$.
+
+\subsection{glp\_read\_ccdata---read graph from text file in DIMACS
+clique/coloring format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_ccdata(glp_graph *G, int v_wgt,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine {\it glp\_read\_ccdata} reads a graph from a text file in
+DIMACS clique/coloring format. (Though this format is originally
+designed to represent data for the minimal vertex coloring and maximal
+clique problems, it may be used to represent general undirected and
+directed graphs, because the routine allows reading self-loops and
+multiple edges/arcs keeping the order of vertices specified for each
+edge/arc of the graph.)
+
+The parameter $G$ specifies the graph object to be read in. Note that
+before reading data the current content of the graph object is
+completely erased with the routine {\it glp\_erase\_graph}.
+
+The parameter {\it v\_wgt} specifies an offset of the field of type
+{\bf double} in the vertex data block, to which the routine stores the
+vertex weight. If {\it v\_wgt} $<0$, the vertex weights are not stored.
+
+The character string {\it fname} specifies the name of a text file to
+be read in. (If the file name ends with the suffix `\verb|.gz|', the
+file is assumed to be compressed, in which case the routine decompresses
+it ``on the fly''.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\subsubsection*{DIMACS clique/coloring format\footnote{This material is
+based on the paper ``Clique and Coloring Problems Graph Format'', which
+is publically available at
+{\tt http://dimacs.rutgers.edu/Challenges/}.}}
+
+The DIMACS input file is a plain ASCII text file. It contains
+{\it lines} of several types described below. A line is terminated with
+an end-of-line character. Fields in each line are separated by at least
+one blank space. Each line begins with a one-character designator to
+identify the line type.
+
+Note that DIMACS requires all numerical quantities to be integers in
+the range $[-2^{31},2^{31}-1]$ while GLPK allows the quantities to be
+floating-point numbers.
+
+\paragraph{Comment lines.} Comment lines give human-readable information
+about the file and are ignored by programs. Comment lines can appear
+anywhere in the file. Each comment line begins with a lower-case
+character \verb|c|.
+
+\begin{verbatim}
+   c This is a comment line
+\end{verbatim}
+
+\paragraph{Problem line.} There is one problem line per data file. The
+problem line must appear before any node or edge descriptor lines. It
+has the following format:
+
+\begin{verbatim}
+   p edge NODES EDGES
+\end{verbatim}
+
+\noindent
+The lower-case letter \verb|p| signifies that this is a problem line.
+The four-character problem designator \verb|edge| identifies the file
+as containing data for the minimal vertex coloring or maximal clique
+problem. The \verb|NODES| field contains an integer value specifying
+the number of vertices in the graph. The \verb|EDGES| field contains an
+integer value specifying the number of edges (arcs) in the graph.
+
+\paragraph{Vertex descriptors.} These lines give the weight assigned to
+a vertex of the graph. There is one vertex descriptor line for each
+vertex, with the following format. Vertices without a descriptor take on
+a default value of 1.
+
+\begin{verbatim}
+   n ID VALUE
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|n| signifies that this is a vertex
+descriptor line. The \verb|ID| field gives a vertex identification
+number, an integer between 1 and $n$, where $n$ is the number of
+vertices in the graph. The \verb|VALUE| field gives a vertex weight,
+which can either positive or negative (or zero).
+
+\paragraph{Edge descriptors.} There is one edge descriptor line for
+each edge (arc) of the graph, each with the following format:
+
+\begin{verbatim}
+   e I J
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|e| signifies that this is an edge
+descriptor line. For an edge (arc) $(i,j)$ the fields \verb|I| and
+\verb|J| specify its endpoints.
+
+\paragraph{Example.} The following example of an undirected graph:
+
+\bigskip
+
+\noindent\hfil
+\xymatrix %@C=32pt
+{&{v_1}\ar@{-}[ldd]\ar@{-}[dd]\ar@{-}[rd]\ar@{-}[rr]&&{v_2}\ar@{-}[ld]
+\ar@{-}[dd]\ar@{-}[rdd]&\\
+&&{v_7}\ar@{-}[ld]\ar@{-}[rd]&&\\
+{v_6}\ar@{-}[r]\ar@{-}[rdd]&{v_{10}}\ar@{-}[rr]\ar@{-}[rd]\ar@{-}[dd]&&
+{v_8}\ar@{-}[ld]\ar@{-}[dd]\ar@{-}[r]&{v_3}\ar@{-}[ldd]\\
+&&{v_9}\ar@{-}[ld]\ar@{-}[rd]&&\\
+&{v_5}\ar@{-}[rr]&&{v_4}&\\
+}
+
+\bigskip
+
+\noindent
+might be coded in DIMACS clique/coloring format as follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+c sample.col
+c
+c This is an example of the vertex coloring problem data
+c in DIMACS format.
+c
+p edge 10 21
+c
+e 1 2
+e 1 6
+e 1 7
+e 1 10
+e 2 3
+e 2 7
+e 2 8
+e 3 4
+e 3 8
+e 4 5
+e 4 8
+e 4 9
+e 5 6
+e 5 9
+e 5 10
+e 6 10
+e 7 8
+e 7 10
+e 8 9
+e 8 10
+e 9 10
+c
+c eof
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_write\_ccdata---write graph to text file in DIMACS
+clique/coloring format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_ccdata(glp_graph *G, int v_wgt,
+      const char *fname);
+\end{verbatim}
+
+\subsection*{Description}
+
+The routine {\it glp\_write\_ccdata} writes the graph object specified
+by the parameter $G$ to a text file in DIMACS clique/coloring format.
+(Though this format is originally designed to represent data for the
+minimal vertex coloring and maximal clique problems, it may be used to
+represent general undirected and directed graphs, because the routine
+allows writing self-loops and multiple edges/arcs keeping the order of
+vertices specified for each edge/arc of the graph.)
+
+The parameter {\it v\_wgt} specifies an offset of the field of type
+{\bf double} in the vertex data block, which contains the vertex weight.
+If {\it v\_wgt} $<0$, it is assumed that the weight of each vertex is 1.
+
+The character string {\it fname} specifies a name of the text file to be
+written out. (If the file name ends with suffix `\verb|.gz|', the file
+is assumed to be compressed, in which case the routine performs
+automatic compression on writing it.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\newpage
+
+\section{Graph analysis routines}
+
+\subsection{glp\_weak\_comp---find all weakly connected components of
+graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_weak_comp(glp_graph *G, int v_num);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_weak_comp| finds all weakly connected components
+of the specified graph.
+
+The parameter \verb|v_num| specifies an offset of the field of type
+\verb|int| in the vertex data block, to which the routine stores the
+number of a weakly connected component containing that vertex. If
+\verb|v_num| $<0$, no component numbers are stored.
+
+The components are numbered in arbitrary order from 1 to \verb|nc|,
+where \verb|nc| is the total number of components found,
+$0\leq$ \verb|nc| $\leq|V|$.
+
+\subsubsection*{Returns}
+
+The routine returns \verb|nc|, the total number of components found.
+
+\subsection{glp\_strong\_comp---find all strongly connected components
+of graph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_strong_comp(glp_graph *G, int v_num);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_strong_comp| finds all strongly connected
+components of the specified graph.
+
+The parameter \verb|v_num| specifies an offset of the field of type
+\verb|int| in the vertex data block, to which the routine stores the
+number of a strongly connected component containing that vertex. If
+\verb|v_num| $<0$, no component numbers are stored.
+
+The components are numbered in arbitrary order from 1 to \verb|nc|,
+where \verb|nc| is the total number of components found,
+$0\leq$ \verb|nc| $\leq|V|$. However, the component numbering has the
+property that for every arc $(i\rightarrow j)$ in the graph the
+condition $num(i)\geq num(j)$ holds.
+
+\subsubsection*{Returns}
+
+The routine returns \verb|nc|, the total number of components found.
+
+\subsubsection*{References}
+
+I.~S.~Duff, J.~K.~Reid, Algorithm 529: Permutations to block triangular
+form, ACM Trans. on Math. Softw. 4 (1978), 189-92.
+
+\subsubsection*{Example}
+
+The following program reads a graph from a plain text file
+`\verb|graph.txt|' and finds all its strongly connected components.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { int num; } v_data;
+
+#define vertex(v) ((v_data *)((v)->data))
+
+int main(void)
+{     glp_graph *G;
+      int i, nc;
+      G = glp_create_graph(sizeof(v_data), 0);
+      glp_read_graph(G, "graph.txt");
+      nc = glp_strong_comp(G, offsetof(v_data, num));
+      printf("nc = %d\n", nc);
+      for (i = 1; i <= G->nv; i++)
+         printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+If the file `\verb|graph.txt|' contains the graph shown below:
+
+\bigskip
+
+\noindent\hfil
+\xymatrix
+{1\ar[r]&2\ar[r]&3\ar[r]\ar[dd]&4\ar[dd]\\
+5\ar[u]&6\ar[l]\\
+7\ar[u]&&8\ar[lu]\ar[ll]\ar[r]&9\ar[r]&10\ar[r]\ar[d]&11\ar[d]\\
+12\ar[u]\ar[rru]\ar@/_/[rr]&&13\ar[ll]\ar[u]\ar[rr]&&14\ar[lu]&15\ar[l]
+\\
+}
+
+\bigskip\bigskip
+
+\noindent
+the program output may look like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading graph from `graph.txt'...
+Graph has 15 vertices and 30 arcs
+31 lines were read
+nc = 4
+num[1] = 3
+num[2] = 3
+num[3] = 3
+num[4] = 2
+num[5] = 3
+num[6] = 3
+num[7] = 3
+num[8] = 3
+num[9] = 1
+num[10] = 1
+num[11] = 1
+num[12] = 4
+num[13] = 4
+num[14] = 1
+num[15] = 1
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_top\_sort---topological sorting of acyclic digraph}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_top_sort(glp_graph *G, int v_num);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_top_sort| performs topological sorting of
+vertices of the specified acyclic digraph.
+
+The parameter \verb|v_num| specifies an offset of the field of type
+\verb|int| in the vertex data block, to which the routine stores the
+vertex number assigned. If \verb|v_num| $<0$, vertex numbers are not
+stored.
+
+The vertices are numbered from 1 to $n$, where $n$ is the total number
+of vertices in the graph. The vertex numbering has the property that
+for every arc $(i\rightarrow j)$ in the graph the condition
+$num(i)<num(j)$ holds. Special case $num(i)=0$ means that vertex $i$ is
+not assigned a number, because the graph is {\it not} acyclic.
+
+\subsubsection*{Returns}
+
+If the graph is acyclic and therefore all the vertices have been
+assigned numbers, the routine \verb|glp_top_sort| returns zero.
+Otherwise, if the graph is not acyclic, the routine returns the number
+of vertices which have not been numbered, i.e. for which $num(i)=0$.
+
+\subsubsection*{Example}
+
+The following program reads a digraph from a plain text file
+`\verb|graph.txt|' and performs topological sorting of its vertices.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { int num; } v_data;
+
+#define vertex(v) ((v_data *)((v)->data))
+
+int main(void)
+{     glp_graph *G;
+      int i, cnt;
+      G = glp_create_graph(sizeof(v_data), 0);
+      glp_read_graph(G, "graph.txt");
+      cnt = glp_top_sort(G, offsetof(v_data, num));
+      printf("cnt = %d\n", cnt);
+      for (i = 1; i <= G->nv; i++)
+         printf("num[%d] = %d\n", i, vertex(G->v[i])->num);
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+If the file `\verb|graph.txt|' contains the graph shown below:
+
+\bigskip
+
+\noindent\hfil
+\xymatrix @=20pt
+{
+1\ar[rrr]&&&2\ar[r]\ar[rddd]&3\ar[rd]&&&&\\
+&&&4\ar[ru]&&5\ar[r]&6\ar[rd]\ar[dd]&&\\
+7\ar[r]&8\ar[r]&9\ar[ruu]\ar[ru]\ar[r]\ar[rd]&10\ar[rr]\ar[rru]&&
+11\ar[ru]&&12\ar[r]&13\\
+&&&14\ar[r]&15\ar[rrru]\ar[rr]&&16\ar[rru]\ar[rr]&&17\\
+}
+
+\bigskip\bigskip
+
+\noindent
+the program output may look like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading graph from `graph.txt'...
+Graph has 17 vertices and 23 arcs
+24 lines were read
+cnt = 0
+num[1] = 8
+num[2] = 9
+num[3] = 10
+num[4] = 4
+num[5] = 11
+num[6] = 12
+num[7] = 1
+num[8] = 2
+num[9] = 3
+num[10] = 5
+num[11] = 6
+num[12] = 14
+num[13] = 16
+num[14] = 7
+num[15] = 13
+num[16] = 15
+num[17] = 17
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+The output corresponds to the following vertex numbering:
+
+\bigskip
+
+\noindent\hfil
+\xymatrix @=20pt
+{
+8\ar[rrr]&&&9\ar[r]\ar[rddd]&10\ar[rd]&&&&\\
+&&&4\ar[ru]&&11\ar[r]&12\ar[rd]\ar[dd]&&\\
+1\ar[r]&2\ar[r]&3\ar[ruu]\ar[ru]\ar[r]\ar[rd]&5\ar[rr]\ar[rru]&&
+6\ar[ru]&&14\ar[r]&16\\
+&&&7\ar[r]&13\ar[rrru]\ar[rr]&&15\ar[rru]\ar[rr]&&17\\
+}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\chapter{Network optimization API routines}
+
+\section{Minimum cost flow problem}
+
+\subsection{Background}
+
+The {\it minimum cost flow problem} (MCFP) is stated as follows. Let
+there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
+a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
+Let for each node $i\in V$ there be given a quantity $b_i$ having the
+following meaning:
+
+if $b_i>0$, then $|b_i|$ is a {\it supply} at node $i$, which shows
+how many flow units are {\it generated} at node $i$ (or, equivalently,
+entering the network through node $i$ from the outside);
+
+if $b_i<0$, then $|b_i|$ is a {\it demand} at node $i$, which shows how
+many flow units are {\it lost} at node $i$ (or, equivalently, leaving
+the network through node $i$ to the outside);
+
+if $b_i=0$, then $i$ is a {\it transshipment} node, at which the flow
+is conserved, i.e. neither generated nor lost.
+
+Let also for each arc $a=(i,j)\in A$ there be given the following three
+quantities:
+
+$l_{ij}$, a (non-negative) lower bound to the flow through arc $(i,j)$;
+
+$u_{ij}$, an upper bound to the flow through arc $(i,j)$, which is the
+{\it arc capacity};
+
+$c_{ij}$, a per-unit cost of the flow through arc $(i,j)$.
+
+The problem is to find flows $x_{ij}$ through every arc of the network,
+which satisfy the specified bounds and the conservation constraints at
+all nodes, and minimize the total flow cost. Here the conservation
+constraint at a node means that the total flow entering this node
+through its incoming arcs plus the supply at this node must be equal to
+the total flow leaving this node through its outgoing arcs plus the
+demand at this node.
+
+An example of the minimum cost flow problem is shown on Fig.~1.
+
+\bigskip
+
+\noindent\hfil
+\xymatrix @C=48pt
+{_{20}\ar@{~>}[d]&
+v_2\ar[r]|{_{0,10,\$2}}\ar[dd]|{_{0,9,\$3}}&
+v_3\ar[dd]|{_{2,12,\$1}}\ar[r]|{_{0,18,\$0}}&
+v_8\ar[rd]|{_{0,20,\$9}}&\\
+v_1\ar[ru]|{_{0,14,\$0}}\ar[rd]|{_{0,23,\$0}}&&&
+v_6\ar[d]|{_{0,7,\$0}}\ar[u]|{_{4,8,\$0}}&
+v_9\ar@{~>}[d]\\
+&v_4\ar[r]|{_{0,26,\$0}}&
+v_5\ar[luu]|{_{0,11,\$1}}\ar[ru]|{_{0,25,\$5}}\ar[r]|{_{0,4,\$7}}&
+v_7\ar[ru]|{_{0,15,\$3}}&_{20}\\
+}
+
+\medskip
+
+\noindent\hfil
+\begin{tabular}{ccc}
+\xymatrix @C=48pt{v_i\ar[r]|{\ l,u,\$c\ }&v_j\\}&
+\xymatrix{\hbox{\footnotesize supply}\ar@{~>}[r]&v_i\\}&
+\xymatrix{v_i\ar@{~>}[r]&\hbox{\footnotesize demand}\\}\\
+\end{tabular}
+
+\bigskip
+
+\noindent\hfil
+Fig.~1. An example of the minimum cost flow problem.
+
+\bigskip
+
+The minimum cost flow problem can be naturally formulated as the
+following LP problem:
+
+\medskip
+
+\noindent
+\hspace{.5in}minimize
+$$z=\sum_{(i,j)\in A}c_{ij}x_{ij}\eqno(1)$$
+\hspace{.5in}subject to
+$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=b_i\ \ \ \hbox
+{for all}\ i\in V\eqno(2)$$
+$$l_{ij}\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
+\eqno(3)$$
+
+\newpage
+
+\subsection{glp\_read\_mincost---read minimum cost flow problem\\data
+in DIMACS format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_mincost(glp_graph *G, int v_rhs, int a_low,
+      int a_cap, int a_cost, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_mincost| reads the minimum cost flow problem
+data from a text file in DIMACS format.
+
+The parameter \verb|G| specifies the graph object, to which the problem
+data have to be stored. Note that before reading data the current
+content of the graph object is completely erased with the routine
+\verb|glp_erase_graph|.
+
+The parameter \verb|v_rhs| specifies an offset of the field of type
+\verb|double| in the vertex data block, to which the routine stores
+$b_i$, the supply/demand value. If \verb|v_rhs| $<0$, the value is not
+stored.
+
+The parameter \verb|a_low| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores
+$l_{ij}$, the lower bound to the arc flow. If \verb|a_low| $<0$, the
+lower bound is not stored.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores
+$u_{ij}$, the upper bound to the arc flow (the arc capacity). If
+\verb|a_cap| $<0$, the upper bound is not stored.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores
+$c_{ij}$, the per-unit cost of the arc flow. If \verb|a_cost| $<0$, the
+cost is not stored.
+
+The character string \verb|fname| specifies the name of a text file to
+be read in. (If the file name name ends with the suffix `\verb|.gz|',
+the file is assumed to be compressed, in which case the routine
+decompresses it ``on the fly''.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\newpage
+
+\subsubsection*{Example}
+
+\begin{footnotesize}
+\begin{verbatim}
+typedef struct
+{     /* vertex data block */
+      ...
+      double rhs;
+      ...
+} v_data;
+
+typedef struct
+{     /* arc data block */
+      ...
+      double low, cap, cost;
+      ...
+} a_data;
+
+int main(void)
+{     glp_graph *G;
+      int ret;
+      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
+      ret = glp_read_mincost(G, offsetof(v_data, rhs),
+         offsetof(a_data, low), offsetof(a_data, cap),
+         offsetof(a_data, cost), "sample.min");
+      if (ret != 0) goto ...
+      ...
+}
+\end{verbatim}
+\end{footnotesize}
+
+\subsubsection*{DIMACS minimum cost flow problem format\footnote{This
+material is based on the paper ``The First DIMACS International
+Algorithm Implementation Challenge: Problem Definitions and
+Specifications'', which is publically available at
+{\tt http://dimacs.rutgers.edu/Challenges/}.}}
+\label{subsecmincost}
+
+The DIMACS input file is a plain ASCII text file. It contains
+{\it lines} of several types described below. A line is terminated with
+an end-of-line character. Fields in each line are separated by at least
+one blank space. Each line begins with a one-character designator to
+identify the line type.
+
+Note that DIMACS requires all numerical quantities to be integers in
+the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
+floating-point numbers.
+
+\newpage
+
+\paragraph{Comment lines.} Comment lines give human-readable information
+about the file and are ignored by programs. Comment lines can appear
+anywhere in the file. Each comment line begins with a lower-case
+character \verb|c|.
+
+\begin{verbatim}
+   c This is a comment line
+\end{verbatim}
+
+\paragraph{Problem line.} There is one problem line per data file. The
+problem line must appear before any node or arc descriptor lines. It has
+the following format:
+
+\begin{verbatim}
+   p min NODES ARCS
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|p| signifies that this is a problem line.
+The three-character problem designator \verb|min| identifies the file as
+containing specification information for the minimum cost flow problem.
+The \verb|NODES| field contains an integer value specifying the number
+of nodes in the network. The \verb|ARCS| field contains an integer value
+specifying the number of arcs in the network.
+
+\paragraph{Node descriptors.} All node descriptor lines must appear
+before all arc descriptor lines. The node descriptor lines describe
+supply and demand nodes, but not transshipment nodes. That is, only
+nodes with non-zero node supply/demand values appear. There is one node
+descriptor line for each such node, with the following format:
+
+\begin{verbatim}
+   n ID FLOW
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|n| signifies that this is a node
+descriptor line. The \verb|ID| field gives a node identification number,
+an integer between 1 and \verb|NODES|. The \verb|FLOW| field gives the
+amount of supply (if positive) or demand (if negative) at node
+\verb|ID|.
+
+\paragraph{Arc descriptors.} There is one arc descriptor line for each
+arc in the network. Arc descriptor lines are of the following format:
+
+\begin{verbatim}
+   a SRC DST LOW CAP COST
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|a| signifies that this is an arc
+descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
+the identification number $i$ for the tail endpoint, and the \verb|DST|
+field gives the identification number $j$ for the head endpoint.
+Identification numbers are integers between 1 and \verb|NODES|. The
+\verb|LOW| field specifies the minimum amount of flow that can be sent
+along arc $(i,j)$, and the \verb|CAP| field gives the maximum amount of
+flow that can be sent along arc $(i,j)$ in a feasible flow. The
+\verb|COST| field contains the per-unit cost of flow sent along arc
+$(i,j)$.
+
+\paragraph{Example.} Below here is an example of the data file in
+DIMACS format corresponding to the minimum cost flow problem shown on
+Fig~1.
+
+\begin{footnotesize}
+\begin{verbatim}
+c sample.min
+c
+c This is an example of the minimum cost flow problem data
+c in DIMACS format.
+c
+p min 9 14
+c
+n 1 20
+n 9 -20
+c
+a 1 2 0 14 0
+a 1 4 0 23 0
+a 2 3 0 10 2
+a 2 4 0  9 3
+a 3 5 2 12 1
+a 3 8 0 18 0
+a 4 5 0 26 0
+a 5 2 0 11 1
+a 5 6 0 25 5
+a 5 7 0  4 7
+a 6 7 0  7 0
+a 6 8 4  8 0
+a 7 9 0 15 3
+a 8 9 0 20 9
+c
+c eof
+\end{verbatim}
+\end{footnotesize}
+
+\newpage
+
+\subsection{glp\_write\_mincost---write minimum cost flow problem\\data
+in DIMACS format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_mincost(glp_graph *G, int v_rhs, int a_low,
+      int a_cap, int a_cost, const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_mincost| writes the minimum cost flow
+problem data to a text file in DIMACS format.
+
+The parameter \verb|G| is the graph (network) program object, which
+specifies the minimum cost flow problem instance.
+
+The parameter \verb|v_rhs| specifies an offset of the field of type
+\verb|double| in the vertex data block, which contains $b_i$, the
+supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
+for all nodes.
+
+The parameter \verb|a_low| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $l_{ij}$, the lower
+bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
+$l_{ij}=0$ for all arcs.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $u_{ij}$, the upper
+bound to the arc flow (the arc capacity). If the upper bound is
+specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
+the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
+$u_{ij}=1$ for all arcs.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $c_{ij}$, the
+per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
+$c_{ij}=0$ for all arcs.
+
+The character string \verb|fname| specifies a name of the text file to
+be written out. (If the file name ends with suffix `\verb|.gz|', the
+file is assumed to be compressed, in which case the routine performs
+automatic compression on writing it.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\newpage
+
+\subsection{glp\_mincost\_lp---convert minimum cost flow problem\\to LP}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
+      int v_rhs, int a_low, int a_cap, int a_cost);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mincost_lp| builds LP problem (1)---(3), which
+corresponds to the specified minimum cost flow problem.
+
+The parameter \verb|lp| is the resultant LP problem object to be built.
+Note that on entry its current content is erased with the routine
+\verb|glp_erase_prob|.
+
+The parameter \verb|G| is the graph (network) program object, which
+specifies the minimum cost flow problem instance.
+
+The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
+routine uses symbolic names of the graph object components to assign
+symbolic names to the LP problem object components. If the flag is
+\verb|GLP_OFF|, no symbolic names are assigned.
+
+The parameter \verb|v_rhs| specifies an offset of the field of type
+\verb|double| in the vertex data block, which contains $b_i$, the
+supply/demand value. If \verb|v_rhs| $<0$, it is assumed that $b_i=0$
+for all nodes.
+
+The parameter \verb|a_low| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $l_{ij}$, the lower
+bound to the arc flow. If \verb|a_low| $<0$, it is assumed that
+$l_{ij}=0$ for all arcs.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $u_{ij}$, the upper
+bound to the arc flow (the arc capacity). If the upper bound is
+specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
+the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
+$u_{ij}=1$ for all arcs.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $c_{ij}$, the
+per-unit cost of the arc flow. If \verb|a_cost| $<0$, it is assumed that
+$c_{ij}=0$ for all arcs.
+
+\subsubsection*{Example}
+
+The example program below reads the minimum cost problem instance in
+DIMACS format from file `\verb|sample.min|', converts the instance to
+LP, and then writes the resultant LP in CPLEX format to file
+`\verb|mincost.lp|'.
+
+\newpage
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <glpk.h>
+
+typedef struct { double rhs; } v_data;
+typedef struct { double low, cap, cost; } a_data;
+
+int main(void)
+{     glp_graph *G;
+      glp_prob *lp;
+      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
+      glp_read_mincost(G, offsetof(v_data, rhs),
+         offsetof(a_data, low), offsetof(a_data, cap),
+         offsetof(a_data, cost), "sample.min");
+      lp = glp_create_prob();
+      glp_mincost_lp(lp, G, GLP_ON, offsetof(v_data, rhs),
+         offsetof(a_data, low), offsetof(a_data, cap),
+         offsetof(a_data, cost));
+      glp_delete_graph(G);
+      glp_write_lp(lp, NULL, "mincost.lp");
+      glp_delete_prob(lp);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+If `\verb|sample.min|' is the example data file from the subsection
+describing the routine \verb|glp_read_mincost|, file `\verb|mincost.lp|'
+may look like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Minimize
+ obj: + 3 x(2,4) + 2 x(2,3) + x(3,5) + 7 x(5,7) + 5 x(5,6)
+ + x(5,2) + 3 x(7,9) + 9 x(8,9)
+
+Subject To
+ r_1: + x(1,2) + x(1,4) = 20
+ r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
+ r_3: + x(3,5) + x(3,8) - x(2,3) = 0
+ r_4: + x(4,5) - x(2,4) - x(1,4) = 0
+ r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
+ r_6: + x(6,7) + x(6,8) - x(5,6) = 0
+ r_7: + x(7,9) - x(6,7) - x(5,7) = 0
+ r_8: + x(8,9) - x(6,8) - x(3,8) = 0
+ r_9: - x(8,9) - x(7,9) = -20
+
+Bounds
+ 0 <= x(1,4) <= 23
+ 0 <= x(1,2) <= 14
+ 0 <= x(2,4) <= 9
+ 0 <= x(2,3) <= 10
+ 0 <= x(3,8) <= 18
+ 2 <= x(3,5) <= 12
+ 0 <= x(4,5) <= 26
+ 0 <= x(5,7) <= 4
+ 0 <= x(5,6) <= 25
+ 0 <= x(5,2) <= 11
+ 4 <= x(6,8) <= 8
+ 0 <= x(6,7) <= 7
+ 0 <= x(7,9) <= 15
+ 0 <= x(8,9) <= 20
+
+End
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_mincost\_okalg---solve minimum cost flow problem with
+out-of-kilter algorithm}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low,
+      int a_cap, int a_cost, double *sol, int a_x, int v_pi);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mincost_okalg| finds optimal solution to the
+minimum cost flow problem with the out-of-kilter
+algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
+is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
+``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
+Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
+routine requires all the problem data to be integer-valued.
+
+The parameter \verb|G| is a graph (network) program object which
+specifies the minimum cost flow problem instance to be solved.
+
+The parameter \verb|v_rhs| specifies an offset of the field of type
+\verb|double| in the vertex data block, which contains $b_i$, the
+supply/demand value. This value must be integer in the range
+[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|v_rhs| $<0$, it is
+assumed that $b_i=0$ for all nodes.
+
+The parameter \verb|a_low| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $l_{ij}$, the lower
+bound to the arc flow. This bound must be integer in the range
+[$0$, \verb|INT_MAX|]. If \verb|a_low| $<0$, it is assumed that
+$l_{ij}=0$ for all arcs.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $u_{ij}$, the upper
+bound to the arc flow (the arc capacity). This bound must be integer in
+the range [$l_{ij}$, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is
+assumed that $u_{ij}=1$ for all arcs.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $c_{ij}$, the
+per-unit cost of the arc flow. This value must be integer in the range
+[$-$\verb|INT_MAX|, $+$\verb|INT_MAX|]. If \verb|a_cost| $<0$, it is
+assumed that $c_{ij}=0$ for all arcs.
+
+The parameter \verb|sol| specifies a location, to which the routine
+stores the objective value (that is, the total cost) found. If
+\verb|sol| is NULL, the objective value is not stored.
+
+The parameter \verb|a_x| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores
+$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow value is
+not stored.
+
+The parameter \verb|v_pi| specifies an offset of the field of type
+\verb|double| in the vertex data block, to which the routine stores
+$\pi_i$, the node potential, which is the Lagrange multiplier for the
+corresponding flow conservation equality constraint (see (2) in
+Subsection ``Background''). If necessary, the application program may
+use the node potentials to compute $\lambda_{ij}$, reduced costs of the
+arc flows $x_{ij}$, which are the Lagrange multipliers for the arc flow
+bound constraints (see (3) ibid.), using the following formula:
+$$\lambda_{ij}=c_{ij}-(\pi_i-\pi_j),$$
+where $c_{ij}$ is the per-unit cost for arc $(i,j)$.
+
+Note that all solution components (the objective value, arc flows, and
+node potentials) computed by the routine are always integer-valued.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & Optimal solution found.\\
+\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
+\verb|GLP_EDATA| & Unable to start the search, because some problem
+data are either not integer-valued or out of range. This code is also
+returned if the total supply, which is the sum of $b_i$ over all source
+nodes (nodes with $b_i>0$), exceeds \verb|INT_MAX|.\\
+\end{tabular}
+
+\noindent
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+\verb|GLP_ERANGE| & The search was prematurely terminated because of
+integer overflow.\\
+\verb|GLP_EFAIL| & An error has been detected in the program logic.
+(If this code is returned for your problem instance, please report to
+\verb|<bug-glpk@gnu.org>|.)\\
+\end{tabular}
+
+\subsubsection*{Comments}
+
+By design the out-of-kilter algorithm is applicable only to networks,
+where $b_i=0$ for {\it all} nodes, i.e. actually this algorithm finds a
+minimal cost {\it circulation}. Due to this requirement the routine
+\verb|glp_mincost_okalg| converts the original network to a network
+suitable for the out-of-kilter algorithm in the following
+way:\footnote{The conversion is performed internally and does not change
+the original network program object passed to the routine.}
+
+1) it adds two auxiliary nodes $s$ and $t$;
+
+2) for each original node $i$ with $b_i>0$ the routine adds auxiliary
+supply arc $(s\rightarrow i)$, flow $x_{si}$ through which is costless
+($c_{si}=0$) and fixed to $+b_i$ ($l_{si}=u_{si}=+b_i$);
+
+3) for each original node $i$ with $b_i<0$ the routine adds auxiliary
+demand arc $(i\rightarrow t)$, flow $x_{it}$ through which is costless
+($c_{it}=0$) and fixed to $-b_i$ ($l_{it}=u_{it}=-b_i$);
+
+4) finally, the routine adds auxiliary feedback arc $(t\rightarrow s)$,
+flow $x_{ts}$ through which is also costless ($c_{ts}=0$) and fixed to
+$F$ ($l_{ts}=u_{ts}=F$), where $\displaystyle F=\sum_{b_i>0}b_i$ is the
+total supply.
+
+\subsubsection*{Example}
+
+The example program below reads the minimum cost problem instance in
+DIMACS format from file `\verb|sample.min|', solves it by using the
+routine \verb|glp_mincost_okalg|, and writes the solution found to the
+standard output.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { double rhs, pi; } v_data;
+typedef struct { double low, cap, cost, x; } a_data;
+
+#define node(v) ((v_data *)((v)->data))
+#define arc(a)  ((a_data *)((a)->data))
+
+int main(void)
+{     glp_graph *G;
+      glp_vertex *v, *w;
+      glp_arc *a;
+      int i, ret;
+      double sol;
+      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
+      glp_read_mincost(G, offsetof(v_data, rhs),
+         offsetof(a_data, low), offsetof(a_data, cap),
+         offsetof(a_data, cost), "sample.min");
+      ret = glp_mincost_okalg(G, offsetof(v_data, rhs),
+         offsetof(a_data, low), offsetof(a_data, cap),
+         offsetof(a_data, cost), &sol, offsetof(a_data, x),
+         offsetof(v_data, pi));
+      printf("ret = %d; sol = %5g\n", ret, sol);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         printf("node %d:    pi = %5g\n", i, node(v)->pi);
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  w = a->head;
+            printf("arc  %d->%d: x  = %5g; lambda = %5g\n",
+               v->i, w->i, arc(a)->x,
+               arc(a)->cost - (node(v)->pi - node(w)->pi));
+         }
+      }
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+If `\verb|sample.min|' is the example data file from the subsection
+describing the routine \verb|glp_read_mincost|, the output may look like
+follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading min-cost flow problem data from `sample.min'...
+Flow network has 9 nodes and 14 arcs
+24 lines were read
+ret = 0; sol =   213
+node 1:    pi =   -12
+arc  1->4: x  =    13; lambda =     0
+arc  1->2: x  =     7; lambda =     0
+node 2:    pi =   -12
+arc  2->4: x  =     0; lambda =     3
+arc  2->3: x  =     7; lambda =     0
+node 3:    pi =   -14
+arc  3->8: x  =     5; lambda =     0
+arc  3->5: x  =     2; lambda =     3
+node 4:    pi =   -12
+arc  4->5: x  =    13; lambda =     0
+node 5:    pi =   -12
+arc  5->7: x  =     4; lambda =    -1
+arc  5->6: x  =    11; lambda =     0
+arc  5->2: x  =     0; lambda =     1
+node 6:    pi =   -17
+arc  6->8: x  =     4; lambda =     3
+arc  6->7: x  =     7; lambda =    -3
+node 7:    pi =   -20
+arc  7->9: x  =    11; lambda =     0
+node 8:    pi =   -14
+arc  8->9: x  =     9; lambda =     0
+node 9:    pi =   -23
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_netgen---Klingman's network problem generator}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+      const int parm[1+15]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_netgen| is a GLPK version of the network problem
+generator developed by Dr.~Darwin~Klingman.\footnote{D.~Klingman,
+A.~Napier, and J.~Stutz. NETGEN: A program for generating large scale
+capacitated assignment, transportation, and minimum cost flow networks.
+Management Science 20 (1974), 814-20.} It can create capacitated and
+uncapacitated minimum cost flow (or transshipment), transportation, and
+assignment problems.
+
+The parameter \verb|G| specifies the graph object, to which the
+generated  problem data have to be stored. Note that on entry the graph
+object  is erased with the routine \verb|glp_erase_graph|.
+
+The parameter \verb|v_rhs| specifies an offset of the field of type
+\verb|double| in the vertex data block, to which the routine stores the
+supply or  demand value. If \verb|v_rhs| $<0$, the value is not stored.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores the
+arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores the
+per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
+stored.
+
+The array \verb|parm| contains description of the network to be
+generated:
+
+\begin{tabular}{@{}lll@{}}
+\verb|parm[0] |&             &not used\\
+\verb|parm[1] |&\verb|iseed |&8-digit positive random number seed\\
+\verb|parm[2] |&\verb|nprob |&8-digit problem id number\\
+\verb|parm[3] |&\verb|nodes |&total number of nodes\\
+\verb|parm[4] |&\verb|nsorc |&total number of source nodes\\
+&&(including transshipment nodes)\\
+\verb|parm[5] |&\verb|nsink |&total number of sink nodes\\
+&&(including transshipment nodes)\\
+\verb|parm[6] |&\verb|iarcs |&number of arc\\
+\verb|parm[7] |&\verb|mincst|&minimum cost for arcs\\
+\verb|parm[8] |&\verb|maxcst|&maximum cost for arcs\\
+\verb|parm[9] |&\verb|itsup |&total supply\\
+\end{tabular}
+
+\begin{tabular}{@{}lll@{}}
+\verb|parm[10]|&\verb|ntsorc|&number of transshipment source nodes\\
+\verb|parm[11]|&\verb|ntsink|&number of transshipment sink nodes\\
+\verb|parm[12]|&\verb|iphic |&percentage of skeleton arcs to be given
+the maxi-\\&&mum cost\\
+\verb|parm[13]|&\verb|ipcap |&percentage of arcs to be capacitated\\
+\verb|parm[14]|&\verb|mincap|&minimum upper bound for capacitated arcs\\
+\verb|parm[15]|&\verb|maxcap|&maximum upper bound for capacitated arcs\\
+\end{tabular}
+
+\subsubsection*{Notes}
+
+\noindent\indent
+1. The routine generates a transportation problem if:
+$${\tt nsorc}+{\tt nsink}={\tt nodes},
+\  {\tt ntsorc}=0,\ \mbox{and}\ {\tt ntsink}=0.$$
+
+2. The routine generates an assignment problem if the requirements for
+a transportation problem are met and:
+$${\tt nsorc}={\tt nsink}\ \mbox{and}\ {\tt itsup}={\tt nsorc}.$$
+
+3. The routine always generates connected graphs. So, if the number of
+requested arcs has been reached and the generated instance is not fully
+connected, the routine generates a few remaining arcs to ensure
+connectedness. Thus, the actual number of arcs generated by the routine
+may be greater than the requested number of arcs.
+
+\subsubsection*{Returns}
+
+If the instance was successfully generated, the routine
+\verb|glp_netgen| returns zero; otherwise, if specified parameters are
+inconsistent, the routine returns a non-zero error code.
+
+\subsection{glp\_gridgen---grid-like network problem generator}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+      const int parm[1+14]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_gridgen| is a GLPK version of the grid-like
+network problem generator developed by Yusin Lee and Jim
+Orlin.\footnote{Y.~Lee and J.~Orlin. GRIDGEN generator., 1991. The
+original code is publically available from
+{\tt<ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>}.}
+
+The parameter \verb|G| specifies the graph object, to which the
+generated  problem data have to be stored. Note that on entry the graph
+object  is erased with the routine \verb|glp_erase_graph|.
+
+The parameter \verb|v_rhs| specifies an offset of the field of type
+\verb|double| in the vertex data block, to which the routine stores the
+supply or  demand value. If \verb|v_rhs| $<0$, the value is not stored.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores the
+arc capacity. If \verb|a_cap| $<0$, the capacity is not stored.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores the
+per-unit cost if the arc flow. If \verb|a_cost| $<0$, the cost is not
+stored.
+
+The array \verb|parm| contains parameters of the network to be
+generated:
+
+\begin{tabular}{@{}ll@{}}
+\verb|parm[0] |&not used\\
+\verb|parm[1] |&two-ways arcs indicator:\\
+               &1 --- if links in both direction should be generated\\
+               &0 --- otherwise\\
+\verb|parm[2] |&random number seed (a positive integer)\\
+\verb|parm[3] |&number of nodes (the number of nodes generated might
+be\\&slightly different to make the network a grid)\\
+\verb|parm[4] |&grid width\\
+\verb|parm[5] |&number of sources\\
+\verb|parm[6] |&number of sinks\\
+\verb|parm[7] |&average degree\\
+\verb|parm[8] |&total flow\\
+\verb|parm[9] |&distribution of arc costs:\\
+               &1 --- uniform\\
+               &2 --- exponential\\
+\verb|parm[10]|&lower bound for arc cost (uniform)\\
+               &$100\lambda$ (exponential)\\
+\verb|parm[11]|&upper bound for arc cost (uniform)\\
+               &not used (exponential)\\
+\verb|parm[12]|&distribution of arc capacities:\\
+               &1 --- uniform\\
+               &2 --- exponential\\
+\verb|parm[13]|&lower bound for arc capacity (uniform)\\
+               &$100\lambda$ (exponential)\\
+\verb|parm[14]|&upper bound for arc capacity (uniform)\\
+               &not used (exponential)\\
+\end{tabular}
+
+\subsubsection*{Returns}
+
+If the instance was successfully generated, the routine
+\verb|glp_gridgen| returns zero; otherwise, if specified parameters are
+inconsistent, the routine returns a non-zero error code.
+
+\subsubsection*{Comments\footnote{This material is based on comments
+to the original version of GRIDGEN.}}
+
+This network generator generates a grid-like network plus a super node.
+In additional to the arcs connecting the nodes in the grid, there is an
+arc from each supply node to the super node and from the super node to
+each demand node to guarantee feasiblity. These arcs have very high
+costs and very big capacities.
+
+The idea of this network generator is as follows: First, a grid of
+$n_1\times n_2$ is generated. For example, $5\times 3$. The nodes are
+numbered as 1 to 15, and the supernode is numbered as $n_1\times n_2+1$.
+Then arcs between adjacent nodes are generated. For these arcs, the user
+is allowed to specify either to generate two-way arcs or one-way arcs.
+If two-way arcs are to be generated, two arcs, one in each direction,
+will be generated between each adjacent node pairs. Otherwise, only one
+arc will be generated. If this is the case, the arcs will be generated
+in alterntive directions as shown below.
+
+\bigskip
+
+\noindent\hfil
+\xymatrix
+{1\ar[r]\ar[d]&2\ar[r]&3\ar[r]\ar[d]&4\ar[r]&5\ar[d]\\
+6\ar[d]&7\ar[l]\ar[u]&8\ar[l]\ar[d]&9\ar[l]\ar[u]&10\ar[l]\ar[d]\\
+11\ar[r]&12\ar[r]\ar[u]&13\ar[r]&14\ar[r]\ar[u]&15\\
+}
+
+\bigskip
+
+Then the arcs between the super node and the source/sink nodes are added
+as mentioned before. If the number of arcs still doesn't reach the
+requirement, additional arcs will be added by uniformly picking random
+node pairs. There is no checking to prevent multiple arcs between any
+pair of nodes. However, there will be no self-arcs (arcs that poins back
+to its tail node) in the network.
+
+The source and sink nodes are selected uniformly in the network, and
+the imbalances of each source/sink node are also assigned by uniform
+distribution.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Maximum flow problem}
+
+\subsection{Background}
+
+The {\it maximum flow problem} (MAXFLOW) is stated as follows. Let
+there be given a directed graph (flow network) $G=(V,A)$, where $V$ is
+a set of vertices (nodes), and $A\subseteq V\times V$ is a set of arcs.
+Let also for each arc $a=(i,j)\in A$ there be given its capacity
+$u_{ij}$. The problem is, for given {\it source} node $s\in V$ and
+{\it sink} node $t\in V$, to find flows $x_{ij}$ through every arc of
+the network, which satisfy the specified arc capacities and the
+conservation constraints at all nodes, and maximize the total flow $F$
+through the network from $s$ to $t$. Here the conservation constraint
+at a node means that the total flow entering this node through its
+incoming arcs (plus $F$, if it is the source node) must be equal to the
+total flow leaving this node through its outgoing arcs (plus $F$, if it
+is the sink node).
+
+An example of the maximum flow problem, where $s=v_1$ and $t=v_9$, is
+shown on Fig.~2.
+
+\bigskip
+
+\noindent\hfil
+\xymatrix @C=48pt
+{_{F}\ar@{~>}[d]&
+v_2\ar[r]|{_{10}}\ar[dd]|{_{9}}&
+v_3\ar[dd]|{_{12}}\ar[r]|{_{18}}&
+v_8\ar[rd]|{_{20}}&\\
+v_1\ar[ru]|{_{14}}\ar[rd]|{_{23}}&&&
+v_6\ar[d]|{_{7}}\ar[u]|{_{8}}&
+v_9\ar@{~>}[d]\\
+&v_4\ar[r]|{_{26}}&
+v_5\ar[luu]|{_{11}}\ar[ru]|{_{25}}\ar[r]|{_{4}}&
+v_7\ar[ru]|{_{15}}&_{F}\\
+}
+
+\bigskip
+
+\noindent\hfil
+Fig.~2. An example of the maximum flow problem.
+
+\bigskip
+
+The maximum flow problem can be naturally formulated as the following
+LP problem:
+
+\medskip
+
+\noindent
+\hspace{.5in}maximize
+$$F\eqno(4)$$
+\hspace{.5in}subject to
+$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}=\left\{
+\begin{array}{@{\ }rl}
++F,&\hbox{for}\ i=s\\
+ 0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
+-F,&\hbox{for}\ i=t\\
+\end{array}
+\right.\eqno(5)
+$$
+$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
+\eqno(6)$$
+
+\medskip
+
+\noindent
+where $F\geq 0$ is an additional variable playing the role of the
+objective.
+
+\newpage
+
+Another LP formulation of the maximum flow problem, which does not
+include the variable $F$, is the following:
+
+\medskip
+
+\noindent
+\hspace{.5in}maximize
+$$z=\sum_{(s,j)\in A}x_{sj}-\sum_{(j,s)\in A}x_{js}\ (=F)\eqno(7)$$
+\hspace{.5in}subject to
+$$\sum_{(i,j)\in A}x_{ij}-\sum_{(j,i)\in A}x_{ji}\left\{
+\begin{array}{@{\ }rl}
+\geq 0,&\hbox{for}\ i=s\\
+=0,&\hbox{for all}\ i\in V\backslash\{s,t\}\\
+\leq 0,&\hbox{for}\ i=t\\
+\end{array}
+\right.\eqno(8)
+$$
+$$0\leq x_{ij}\leq u_{ij}\ \ \ \hbox{for all}\ (i,j)\in A
+\eqno(9)$$
+
+\subsection{glp\_read\_maxflow---read maximum flow problem data\\in
+DIMACS format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_maxflow| reads the maximum flow problem
+data from a text file in DIMACS format.
+
+The parameter \verb|G| specifies the graph object, to which the problem
+data have to be stored. Note that before reading data the current
+content of the graph object is completely erased with the routine
+\verb|glp_erase_graph|.
+
+The pointer \verb|s| specifies a location, to which the routine stores
+the ordinal number of the source node. If \verb|s| is \verb|NULL|, the
+source node number is not stored.
+
+The pointer \verb|t| specifies a location, to which the routine stores
+the ordinal number of the sink node. If \verb|t| is \verb|NULL|, the
+sink node number is not stored.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores
+$u_{ij}$, the arc capacity. If \verb|a_cap| $<0$, the arc capacity is
+not stored.
+
+The character string \verb|fname| specifies the name of a text file to
+be read in. (If the file name name ends with the suffix `\verb|.gz|',
+the file is assumed to be compressed, in which case the routine
+decompresses it ``on the fly''.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\subsubsection*{Example}
+
+\begin{footnotesize}
+\begin{verbatim}
+typedef struct
+{     /* arc data block */
+      ...
+      double cap;
+      ...
+} a_data;
+
+int main(void)
+{     glp_graph *G;
+      int s, t, ret;
+      G = glp_create_graph(..., sizeof(a_data));
+      ret = glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
+         "sample.max");
+      if (ret != 0) goto ...
+      ...
+}
+\end{verbatim}
+\end{footnotesize}
+
+\subsubsection*{DIMACS maximum flow problem format\footnote{This
+material is based on the paper ``The First DIMACS International
+Algorithm Implementation Challenge: Problem Definitions and
+Specifications'', which is publically available at
+{\tt http://dimacs.rutgers.edu/Challenges/}.}}
+\label{subsecmaxflow}
+
+The DIMACS input file is a plain ASCII text file. It contains
+{\it lines} of several types described below. A line is terminated with
+an end-of-line character. Fields in each line are separated by at least
+one blank space. Each line begins with a one-character designator to
+identify the line type.
+
+Note that DIMACS requires all numerical quantities to be integers in
+the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
+floating-point numbers.
+
+\paragraph{Comment lines.} Comment lines give human-readable information
+about the file and are ignored by programs. Comment lines can appear
+anywhere in the file. Each comment line begins with a lower-case
+character \verb|c|.
+
+\begin{verbatim}
+   c This is a comment line
+\end{verbatim}
+
+\newpage
+
+\paragraph{Problem line.} There is one problem line per data file. The
+problem line must appear before any node or arc descriptor lines. It has
+the following format:
+
+\begin{verbatim}
+   p max NODES ARCS
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|p| signifies that this is a problem line.
+The three-character problem designator \verb|max| identifies the file as
+containing specification information for the maximum flow problem. The
+\verb|NODES| field contains an integer value specifying the number of
+nodes in the network. The \verb|ARCS| field contains an integer value
+specifying the number of arcs in the network.
+
+\paragraph{Node descriptors.} Two node descriptor lines for the source
+and sink nodes must appear before all arc descriptor lines. They may
+appear in either order, each with the following format:
+
+\begin{verbatim}
+   n ID WHICH
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|n| signifies that this a node descriptor
+line. The \verb|ID| field gives a node identification number, an integer
+between 1 and \verb|NODES|. The \verb|WHICH| field gives either a
+lower-case \verb|s| or \verb|t|, designating the source and sink,
+respectively.
+
+\paragraph{Arc descriptors.} There is one arc descriptor line for each
+arc in the network. Arc descriptor lines are of the following format:
+
+\begin{verbatim}
+   a SRC DST CAP
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|a| signifies that this is an arc
+descriptor line. For a directed arc $(i,j)$ the \verb|SRC| field gives
+the identification number $i$ for the tail endpoint, and the \verb|DST|
+field gives the identification number $j$ for the head endpoint.
+Identification numbers are integers between 1 and \verb|NODES|. The
+\verb|CAP| field gives the arc capacity, i.e. maximum amount of flow
+that can be sent along arc $(i,j)$ in a feasible flow.
+
+\paragraph{Example.} Below here is an example of the data file in
+DIMACS format corresponding to the maximum flow problem shown on Fig~2.
+
+\newpage
+
+\begin{footnotesize}
+\begin{verbatim}
+c sample.max
+c
+c This is an example of the maximum flow problem data
+c in DIMACS format.
+c
+p max 9 14
+c
+n 1 s
+n 9 t
+c
+a 1 2 14
+a 1 4 23
+a 2 3 10
+a 2 4  9
+a 3 5 12
+a 3 8 18
+a 4 5 26
+a 5 2 11
+a 5 6 25
+a 5 7  4
+a 6 7  7
+a 6 8  8
+a 7 9 15
+a 8 9 20
+c
+c eof
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_write\_maxflow---write maximum flow problem data\\
+in DIMACS format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_maxflow| writes the maximum flow problem
+data to a text file in DIMACS format.
+
+The parameter \verb|G| is the graph (network) program object, which
+specifies the maximum flow problem instance.
+
+The parameter \verb|s| specifies the ordinal number of the source node.
+
+The parameter \verb|t| specifies the ordinal number of the sink node.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $u_{ij}$, the upper
+bound to the arc flow (the arc capacity). If the upper bound is
+specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
+the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
+$u_{ij}=1$ for all arcs.
+
+The character string \verb|fname| specifies a name of the text file to
+be written out. (If the file name ends with suffix `\verb|.gz|', the
+file is assumed to be compressed, in which case the routine performs
+automatic compression on writing it.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\subsection{glp\_maxflow\_lp---convert maximum flow problem to LP}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names,
+      int s, int t, int a_cap);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_maxflow_lp| builds LP problem (7)---(9), which
+corresponds to the specified maximum flow problem.
+
+The parameter \verb|lp| is the resultant LP problem object to be built.
+Note that on entry its current content is erased with the routine
+\verb|glp_erase_prob|.
+
+The parameter \verb|G| is the graph (network) program object, which
+specifies the maximum flow problem instance.
+
+The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
+routine uses symbolic names of the graph object components to assign
+symbolic names to the LP problem object components. If the flag is
+\verb|GLP_OFF|, no symbolic names are assigned.
+
+The parameter \verb|s| specifies the ordinal number of the source node.
+
+The parameter \verb|t| specifies the ordinal number of the sink node.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $u_{ij}$, the upper
+bound to the arc flow (the arc capacity). If the upper bound is
+specified as \verb|DBL_MAX|, it is assumed that $u_{ij}=\infty$, i.e.
+the arc is uncapacitated. If \verb|a_cap| $<0$, it is assumed that
+$u_{ij}=1$ for all arcs.
+
+\subsubsection*{Example}
+
+The example program below reads the maximum flow problem in DIMACS
+format from file `\verb|sample.max|', converts the instance to LP, and
+then writes the resultant LP in CPLEX format to file
+`\verb|maxflow.lp|'.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_graph *G;
+      glp_prob *lp;
+      int s, t;
+      G = glp_create_graph(0, sizeof(double));
+      glp_read_maxflow(G, &s, &t, 0, "sample.max");
+      lp = glp_create_prob();
+      glp_maxflow_lp(lp, G, GLP_ON, s, t, 0);
+      glp_delete_graph(G);
+      glp_write_lp(lp, NULL, "maxflow.lp");
+      glp_delete_prob(lp);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+If `\verb|sample.max|' is the example data file from the previous
+subsection, the output `\verb|maxflow.lp|' may look like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Maximize
+ obj: + x(1,4) + x(1,2)
+
+Subject To
+ r_1: + x(1,2) + x(1,4) >= 0
+ r_2: - x(5,2) + x(2,3) + x(2,4) - x(1,2) = 0
+ r_3: + x(3,5) + x(3,8) - x(2,3) = 0
+ r_4: + x(4,5) - x(2,4) - x(1,4) = 0
+ r_5: + x(5,2) + x(5,6) + x(5,7) - x(4,5) - x(3,5) = 0
+ r_6: + x(6,7) + x(6,8) - x(5,6) = 0
+ r_7: + x(7,9) - x(6,7) - x(5,7) = 0
+ r_8: + x(8,9) - x(6,8) - x(3,8) = 0
+ r_9: - x(8,9) - x(7,9) <= 0
+
+Bounds
+ 0 <= x(1,4) <= 23
+ 0 <= x(1,2) <= 14
+ 0 <= x(2,4) <= 9
+ 0 <= x(2,3) <= 10
+ 0 <= x(3,8) <= 18
+ 0 <= x(3,5) <= 12
+ 0 <= x(4,5) <= 26
+ 0 <= x(5,7) <= 4
+ 0 <= x(5,6) <= 25
+ 0 <= x(5,2) <= 11
+ 0 <= x(6,8) <= 8
+ 0 <= x(6,7) <= 7
+ 0 <= x(7,9) <= 15
+ 0 <= x(8,9) <= 20
+
+End
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_maxflow\_ffalg---solve maximum flow problem with
+Ford-Fulkerson algorithm}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
+      double *sol, int a_x, int v_cut);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mincost_ffalg| finds optimal solution to the
+maximum flow problem with the Ford-Fulkerson algorithm.\footnote{GLPK
+implementation of the Ford-Fulkerson algorithm is based on the following
+book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson, ``Flows in Networks,'' The
+RAND Corp., Report\linebreak R-375-PR (August 1962), Chap. I
+``Static Maximal Flow,'' pp.~30-33.} Note that this routine requires all
+the problem data to be integer-valued.
+
+The parameter \verb|G| is a graph (network) program object which
+specifies the maximum flow problem instance to be solved.
+
+The parameter $s$ specifies the ordinal number of the source node.
+
+The parameter $t$ specifies the ordinal number of the sink node.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $u_{ij}$, the upper
+bound to the arc flow (the arc capacity). This bound must be integer in
+the range [0, \verb|INT_MAX|]. If \verb|a_cap| $<0$, it is assumed that
+$u_{ij}=1$ for all arcs.
+
+The parameter \verb|sol| specifies a location, to which the routine
+stores the objective value (that is, the total flow from $s$ to $t$)
+found. If \verb|sol| is NULL, the objective value is not stored.
+
+The parameter \verb|a_x| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores
+$x_{ij}$, the arc flow found. If \verb|a_x| $<0$, the arc flow values
+are not stored.
+
+The parameter \verb|v_cut| specifies an offset of the field of type
+\verb|int| in the vertex data block, to which the routine stores node
+flags corresponding to the optimal solution found: if the node flag is
+1, the node is labelled, and if the node flag is 0, the node is
+unlabelled. The calling program may use these node flags to determine
+the {\it minimal cut}, which is a subset of arcs whose one endpoint is
+labelled and other is not. If \verb|v_cut| $<0$, the node flags are not
+stored.
+
+Note that all solution components (the objective value and arc flows)
+computed by the routine are always integer-valued.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & Optimal solution found.\\
+\verb|GLP_EDATA| & Unable to start the search, because some problem
+data are either not integer-valued or out of range.\\
+\end{tabular}
+
+\subsubsection*{Example}
+
+The example program shown below reads the maximum flow problem instance
+in DIMACS format from file `\verb|sample.max|', solves it using the
+routine \verb|glp_maxflow_ffalg|, and write the solution found to the
+standard output.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { int cut; } v_data;
+typedef struct { double cap, x; } a_data;
+
+#define node(v) ((v_data *)((v)->data))
+#define arc(a)  ((a_data *)((a)->data))
+
+int main(void)
+{     glp_graph *G;
+      glp_vertex *v, *w;
+      glp_arc *a;
+      int i, s, t, ret;
+      double sol;
+      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
+      glp_read_maxflow(G, &s, &t, offsetof(a_data, cap),
+         "sample.max");
+      ret = glp_maxflow_ffalg(G, s, t, offsetof(a_data, cap),
+         &sol, offsetof(a_data, x), offsetof(v_data, cut));
+      printf("ret = %d; sol = %5g\n", ret, sol);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  w = a->head;
+            printf("x[%d->%d] = %5g (%d)\n", v->i, w->i,
+               arc(a)->x, node(v)->cut ^ node(w)->cut);
+         }
+      }
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+If `\verb|sample.max|' is the example data file from the subsection
+describing the routine \verb|glp_read_maxflow|, the output may look like
+follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading maximum flow problem data from `sample.max'...
+Flow network has 9 nodes and 14 arcs
+24 lines were read
+ret = 0; sol =    29
+x[1->4] =    19 (0)
+x[1->2] =    10 (0)
+x[2->4] =     0 (0)
+x[2->3] =    10 (1)
+x[3->8] =    10 (0)
+x[3->5] =     0 (1)
+x[4->5] =    19 (0)
+x[5->7] =     4 (1)
+x[5->6] =    15 (0)
+x[5->2] =     0 (0)
+x[6->8] =     8 (1)
+x[6->7] =     7 (1)
+x[7->9] =    11 (0)
+x[8->9] =    18 (0)
+\end{verbatim}
+\end{footnotesize}
+
+\newpage
+
+\subsection{glp\_rmfgen---Goldfarb's maximum flow problem generator}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
+      const int parm[1+5]);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_rmfgen| is a GLPK version of the maximum flow
+problem generator developed by D.~Goldfarb and
+M.~Grigoriadis.\footnote{D.~Goldfarb and M.~D.~Grigoriadis,
+``A computational comparison of the Dinic and network simplex methods
+for maximum flow.'' Annals of Op. Res. 13 (1988),
+pp.~83-123.}$^{,}$\footnote{U.~Derigs and W.~Meier, ``Implementing
+Goldberg's max-flow algorithm: A computational investigation.''
+Zeitschrift f\"ur Operations Research 33 (1989),
+pp.~383-403.}$^{,}$\footnote{The original code of RMFGEN implemented by
+Tamas Badics is publically available from
+{\tt <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>}.}
+
+The parameter \verb|G| specifies the graph object, to which the
+generated problem data have to be stored. Note that on entry the graph
+object is erased with the routine \verb|glp_erase_graph|.
+
+The pointers \verb|s| and \verb|t| specify locations, to which the
+routine stores the source and sink node numbers, respectively. If
+\verb|s| or \verb|t| is \verb|NULL|, corresponding node number is not
+stored.
+
+The parameter \verb|a_cap| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores the arc
+capacity. If \verb|a_cap| $<0$, the capacity is not stored.
+
+The array \verb|parm| contains description of the network to be
+generated:
+
+\begin{tabular}{@{}lll@{}}
+\verb|parm[0]|&           &not used\\
+\verb|parm[1]|&\verb|seed|&random number seed (a positive integer)\\
+\verb|parm[2]|&\verb|a   |&frame size\\
+\verb|parm[3]|&\verb|b   |&depth\\
+\verb|parm[4]|&\verb|c1  |&minimal arc capacity\\
+\verb|parm[5]|&\verb|c2  |&maximal arc capacity\\
+\end{tabular}
+
+\subsubsection*{Returns}
+
+If the instance was successfully generated, the routine
+\verb|glp_netgen| returns zero; otherwise, if specified parameters are
+inconsistent, the routine returns a non-zero error code.
+
+\newpage
+
+\subsubsection*{Comments\footnote{This material is based on comments
+to the original version of RMFGEN.}}
+
+The generated network is as follows. It has $b$ pieces of frames of
+size $a\times a$. (So alltogether the number of vertices is
+$a\times a\times b$.)
+
+In each frame all the vertices are connected with their neighbours
+(forth and back). In addition the vertices of a frame are connected
+one to one with the vertices of next frame using a random permutation
+of those vertices.
+
+The source is the lower left vertex of the first frame, the sink is
+the upper right vertex of the $b$-th frame.
+
+\begin{verbatim}
+                              t
+                     +-------+
+                     |      .|
+                     |     . |
+                  /  |    /  |
+                 +-------+/ -+ b
+                 |    |  |/.
+               a |   -v- |/
+                 |    |  |/
+                 +-------+ 1
+                s    a
+\end{verbatim}
+
+The capacities are randomly chosen integers from the range of
+$[c_1,c_2]$  in the case of interconnecting edges, and $c_2\cdot a^2$
+for the in-frame edges.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Assignment problem}
+
+\subsection{Background}
+
+Let there be given an undirected bipartite graph $G=(R\cup S,E)$, where
+$R$ and $S$ are disjoint sets of vertices (nodes), and
+$E\subseteq R\times S$ is a set of edges. Let also for each edge
+$e=(i,j)\in E$ there be given its cost $c_{ij}$. A {\it matching}
+(which in case of bipartite graph is also called {\it assignment})
+$M\subseteq E$ in $G$ is a set of pairwise non-adjacent edges, that is,
+no two edges in $M$ share a common vertex. A matching, which matches
+all vertices of the graph, is called a {\it perfect matching}.
+Obviously, a perfect matching in bipartite graph $G=(R\cup S,E)$
+defines some bijection $R\leftrightarrow S$.
+
+The {\it assignment problem} has two different variants. In the first
+variant the problem is to find matching (assignment) $M$, which
+maximizes the sum:
+$$\sum_{(i,j)\in M}c_{ij}\eqno(10)$$
+(so this variant is also called the {\it maximum weighted bipartite
+matching problem} or, if all $c_{ij}=1$, the {\it maximum cardinality
+bipartite matching problem}). In the second, classic variant the
+problem is to find {\it perfect} matching (assignment) $M$, which
+minimizes or maximizes the sum (10).
+
+An example of the assignment problem, which is the maximum weighted
+bipartite matching problem, is shown on Fig. 3.
+
+The maximum weighted bipartite matching problem can be naturally
+formulated as the following LP problem:
+
+\medskip
+
+\noindent
+\hspace{.5in}maximize
+$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(11)$$
+\hspace{.5in}subject to
+$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ i\in R\eqno(12)$$
+$$\sum_{(i,j)\in E}x_{ij}\leq 1\ \ \ \hbox{for all}\ j\in S\eqno(13)$$
+$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
+\eqno(14)$$
+
+\medskip
+
+\noindent
+where $x_{ij}=1$ means that $(i,j)\in M$, and $x_{ij}=0$ means that
+$(i,j)\notin M$.\footnote{The constraint matrix of LP formulation
+(11)---(14) is totally unimodular, due to which $x_{ij}\in\{0,1\}$ for
+any basic solution.}
+
+\newpage
+
+\bigskip
+
+\noindent\hfil
+\xymatrix @C=48pt
+{v_1\ar@{-}[rr]|{_{13}}\ar@{-}[rrd]|{_{21}}\ar@{-}[rrddd]|(.2){_{20}}&&
+v_9\\
+v_2\ar@{-}[rr]|{_{12}}\ar@{-}[rrdd]|(.3){_{8}}
+\ar@{-}[rrddd]|(.4){_{26}}&&v_{10}\\
+v_3\ar@{-}[rr]|(.2){_{22}}\ar@{-}[rrdd]|(.3){_{11}}&&v_{11}\\
+v_4\ar@{-}[rruuu]|(.6){_{12}}\ar@{-}[rr]|(.2){_{36}}
+\ar@{-}[rrdd]|(.7){_{25}}&&v_{12}\\
+v_5\ar@{-}[rruu]|(.42){_{41}}\ar@{-}[rru]|(.4){_{40}}
+\ar@{-}[rr]|(.75){_{11}}\ar@{-}[rrd]|(.6){_{4}}\ar@{-}[rrdd]|{_{8}}
+\ar@{-}[rrddd]|{_{35}}\ar@{-}[rrdddd]|{_{32}}&&v_{13}\\
+v_6\ar@{-}[rruuuuu]|(.7){_{13}}&&v_{14}\\
+v_7\ar@{-}[rruuuuu]|(.15){_{19}}&&v_{15}\\
+v_8\ar@{-}[rruuuuuu]|(.25){_{39}}\ar@{-}[rruuuuu]|(.65){_{15}}&&
+v_{16}\\
+&&v_{17}\\
+}
+
+\bigskip
+
+\noindent\hfil
+Fig.~3. An example of the assignment problem.
+
+\bigskip
+
+Similarly, the perfect assignment problem can be naturally formulated
+as the following LP problem:
+
+\medskip
+
+\noindent
+\hspace{.5in}minimize (or maximize)
+$$z=\sum_{(i,j)\in E}c_{ij}x_{ij}\eqno(15)$$
+\hspace{.5in}subject to
+$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ i\in R\eqno(16)$$
+$$\sum_{(i,j)\in E}x_{ij}=1\ \ \ \hbox{for all}\ j\in S\eqno(17)$$
+$$\ \ \ \ \ \ \ \ 0\leq x_{ij}\leq 1\ \ \ \hbox{for all}\ (i,j)\in E
+\eqno(18)$$
+
+\medskip
+
+\noindent
+where variables $x_{ij}$ have the same meaning as for (11)---(14)
+above.
+
+\newpage
+
+In GLPK an undirected bipartite graph $G=(R\cup S,E)$ is represented as
+directed graph $\overline{G}=(V,A)$, where $V=R\cup S$ and
+$A=\{(i,j):(i,j)\in E\}$, i.e. every edge $(i,j)\in E$ in $G$
+corresponds to arc $(i\rightarrow j)\in A$ in $\overline{G}$.
+
+\subsection{glp\_read\_asnprob---read assignment problem data in\\DIMACS
+format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_read_asnprob| reads the assignment problem data
+from a text file in DIMACS format.
+
+The parameter \verb|G| specifies the graph object, to which the problem
+data have to be stored. Note that before reading data the current
+content of the graph object is completely erased with the routine
+\verb|glp_erase_graph|.
+
+The parameter \verb|v_set| specifies an offset of the field of type
+\verb|int| in the vertex data block, to which the routine stores the
+node set indicator:
+
+0 --- the node is in set $R$;
+
+1 --- the node is in set $S$.
+
+\noindent
+If \verb|v_set| $<0$, the node set indicator is not stored.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, to which the routine stores the
+edge cost $c_{ij}$. If \verb|a_cost| $<0$, the edge cost is not stored.
+
+The character string \verb|fname| specifies the name of a text file to
+be read in. (If the file name name ends with the suffix `\verb|.gz|',
+the file is assumed to be compressed, in which case the routine
+decompresses it ``on the fly''.)
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\newpage
+
+\subsubsection*{Example}
+
+\begin{footnotesize}
+\begin{verbatim}
+typedef struct
+{     /* vertex data block */
+      ...
+      int set;
+      ...
+} v_data;
+
+typedef struct
+{     /* arc data block */
+      ...
+      double cost;
+      ...
+} a_data;
+
+int main(void)
+{     glp_graph *G;
+      int ret;
+      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
+      ret = glp_read_asnprob(G, offsetof(v_data, set),
+         offsetof(a_data, cost), "sample.asn");
+      if (ret != 0) goto ...
+      ...
+}
+\end{verbatim}
+\end{footnotesize}
+
+\subsubsection*{DIMACS assignment problem format\footnote{This
+material is based on the paper ``The First DIMACS International
+Algorithm Implementation Challenge: Problem Definitions and
+Specifications'', which is publically available at
+{\tt http://dimacs.rutgers.edu/Challenges/}.}}
+\label{subsecasnprob}
+
+The DIMACS input file is a plain ASCII text file. It contains
+{\it lines} of several types described below. A line is terminated with
+an end-of-line character. Fields in each line are separated by at least
+one blank space. Each line begins with a one-character designator to
+identify the line type.
+
+Note that DIMACS requires all numerical quantities to be integers in
+the range $[-2^{31},\ 2^{31}-1]$ while GLPK allows the quantities to be
+floating-point numbers.
+
+\paragraph{Comment lines.} Comment lines give human-readable information
+about the file and are ignored by programs. Comment lines can appear
+anywhere in the file. Each comment line begins with a lower-case
+character \verb|c|.
+
+\begin{verbatim}
+   c This is a comment line
+\end{verbatim}
+
+\newpage
+
+\paragraph{Problem line.} There is one problem line per data file. The
+problem line must appear before any node or arc descriptor lines. It has
+the following format:
+
+\begin{verbatim}
+   p asn NODES EDGES
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|p| signifies that this is a problem line.
+The three-character problem designator \verb|asn| identifies the file as
+containing specification information for the assignment problem.
+The \verb|NODES| field contains an integer value specifying the total
+number of nodes in the graph (i.e. in both sets $R$ and $S$). The
+\verb|EDGES| field contains an integer value specifying the number of
+edges in the graph.
+
+\paragraph{Node descriptors.} All node descriptor lines must appear
+before all edge descriptor lines. The node descriptor lines lists the
+nodes in set $R$ only, and all other nodes are assumed to be in set
+$S$. There is one node descriptor line for each such node, with the
+following format:
+
+\begin{verbatim}
+   n ID
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|n| signifies that this is a node
+descriptor line. The \verb|ID| field gives a node identification number,
+an integer between 1 and \verb|NODES|.
+
+\paragraph{Edge descriptors.} There is one edge descriptor line for
+each edge in the graph. Edge descriptor lines are of the following
+format:
+
+\begin{verbatim}
+   a SRC DST COST
+\end{verbatim}
+
+\noindent
+The lower-case character \verb|a| signifies that this is an edge
+descriptor line. For each edge $(i,j)$, where $i\in R$ and $j\in S$,
+the \verb|SRC| field gives the identification number of vertex $i$, and
+the \verb|DST| field gives the identification number of vertex $j$.
+Identification numbers are integers between 1 and \verb|NODES|. The
+\verb|COST| field contains the cost of edge $(i,j)$.
+
+\paragraph{Example.} Below here is an example of the data file in
+DIMACS format corresponding to the assignment problem shown on Fig~3.
+
+\newpage
+
+\begin{footnotesize}
+\begin{verbatim}
+c sample.asn
+c
+c This is an example of the assignment problem data
+c in DIMACS format.
+c
+p asn 17 22
+c
+n 1
+n 2
+n 3
+n 4
+n 5
+n 6
+n 7
+n 8
+c
+a 1  9 13
+a 1 10 21
+a 1 12 20
+a 2 10 12
+a 2 12  8
+a 2 13 26
+a 3 11 22
+a 3 13 11
+a 4  9 12
+a 4 12 36
+a 4 14 25
+a 5 11 41
+a 5 12 40
+a 5 13 11
+a 5 14  4
+a 5 15  8
+a 5 16 35
+a 5 17 32
+a 6  9 13
+a 7 10 19
+a 8 10 39
+a 8 11 15
+c
+c eof
+\end{verbatim}
+\end{footnotesize}
+
+\newpage
+
+\subsection{glp\_write\_asnprob---write assignment problem data in\\
+DIMACS format}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
+      const char *fname);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_write_asnprob| writes the assignment problem data
+to a text file in DIMACS format.
+
+The parameter \verb|G| is the graph program object, which specifies the
+assignment problem instance.
+
+The parameter \verb|v_set| specifies an offset of the field of type
+\verb|int| in the vertex data block, which contains the node set
+indicator:
+
+0 --- the node is in set $R$;
+
+1 --- the node is in set $S$.
+
+\noindent
+If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
+is in set $R$, and a node having no outgoing arcs is in set $S$.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $c_{ij}$, the edge
+cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
+edges.
+
+The character string \verb|fname| specifies a name of the text file to
+be written out. (If the file name ends with suffix `\verb|.gz|', the
+file is assumed to be compressed, in which case the routine performs
+automatic compression on writing it.)
+
+\subsubsection*{Note}
+
+The routine \verb|glp_write_asnprob| does not check that the specified
+graph object correctly represents a bipartite graph. To make sure that
+the problem data are correct, use the routine \verb|glp_check_asnprob|.
+
+\subsubsection*{Returns}
+
+If the operation was successful, the routine returns zero. Otherwise,
+it prints an error message and returns non-zero.
+
+\newpage
+
+\subsection{glp\_check\_asnprob---check correctness of assignment
+problem data}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_check_asnprob(glp_graph *G, int v_set);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_check_asnprob| checks that the specified graph
+object \verb|G| correctly represents a bipartite graph.
+
+The parameter \verb|v_set| specifies an offset of the field of type
+\verb|int| in the vertex data block, which contains the node set
+indicator:
+
+0 --- the node is in set $R$;
+
+1 --- the node is in set $S$.
+
+\noindent
+If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
+is in set $R$, and a node having no outgoing arcs is in set $S$.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_check_asnprob| may return the following codes:
+
+0 --- the data are correct;
+
+1 --- the set indicator of some node is 0, however, that node has one
+or more incoming arcs;
+
+2 --- the set indicator of some node is 1, however, that node has one
+or more outgoing arcs;
+
+3 --- the set indicator of some node is invalid (neither 0 nor 1);
+
+4 --- some node has both incoming and outgoing arcs.
+
+\subsection{glp\_asnprob\_lp---convert assignment problem to LP}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G,
+      int names, int v_set, int a_cost);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_asnprob_lp| builds LP problem, which corresponds
+to the specified assignment problem.
+
+The parameter \verb|lp| is the resultant LP problem object to be built.
+Note that on entry its current content is erased with the routine
+\verb|glp_erase_prob|.
+
+The parameter \verb|form| defines which LP formulation should be used:
+
+\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
+
+\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
+
+\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
+
+The parameter \verb|G| is the graph program object, which specifies the
+assignment problem instance.
+
+The parameter \verb|names| is a flag. If it is \verb|GLP_ON|, the
+routine uses symbolic names of the graph object components to assign
+symbolic names to the LP problem object components. If the \verb|flag|
+is \verb|GLP_OFF|, no symbolic names are assigned.
+
+The parameter \verb|v_set| specifies an offset of the field of type
+\verb|int| in the vertex data block, which contains the node set
+indicator:
+
+0 --- the node is in set $R$;
+
+1 --- the node is in set $S$.
+
+\noindent
+If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
+is in set $R$, and a node having no outgoing arcs is in set $S$.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $c_{ij}$, the edge
+cost. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$ for all
+edges.
+
+\subsubsection*{Returns}
+
+If the LP problem has been successfully built, the routine
+\verb|glp_asnprob_lp| returns zero, otherwise, non-zero (see the
+routine \verb|glp_check_asnprob|).
+
+\subsubsection*{Example}
+
+The example program below reads the assignment problem instance in
+DIMACS format from file `\verb|sample.asn|', converts the instance to
+LP (11)---(14), and writes the resultant LP in CPLEX format to file
+`\verb|matching.lp|'.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <glpk.h>
+
+typedef struct { int set; } v_data;
+typedef struct { double cost; } a_data;
+
+int main(void)
+{     glp_graph *G;
+      glp_prob *P;
+      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
+      glp_read_asnprob(G, offsetof(v_data, set),
+         offsetof(a_data, cost), "sample.asn");
+      P = glp_create_prob();
+      glp_asnprob_lp(P, GLP_ASN_MMP, G, GLP_ON,
+         offsetof(v_data, set), offsetof(a_data, cost));
+      glp_delete_graph(G);
+      glp_write_lp(P, NULL, "matching.lp");
+      glp_delete_prob(P);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+If `\verb|sample.asn|' is the example data file from the subsection
+describing the routine \verb|glp_read_asnprob|, file
+`\verb|matching.lp|' may look like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Maximize
+ obj: + 20 x(1,12) + 21 x(1,10) + 13 x(1,9) + 26 x(2,13) + 8 x(2,12)
+ + 12 x(2,10) + 11 x(3,13) + 22 x(3,11) + 25 x(4,14) + 36 x(4,12)
+ + 12 x(4,9) + 32 x(5,17) + 35 x(5,16) + 8 x(5,15) + 4 x(5,14)
+ + 11 x(5,13) + 40 x(5,12) + 41 x(5,11) + 13 x(6,9) + 19 x(7,10)
+ + 15 x(8,11) + 39 x(8,10)
+
+Subject To
+ r_1: + x(1,9) + x(1,10) + x(1,12) <= 1
+ r_2: + x(2,10) + x(2,12) + x(2,13) <= 1
+ r_3: + x(3,11) + x(3,13) <= 1
+ r_4: + x(4,9) + x(4,12) + x(4,14) <= 1
+ r_5: + x(5,11) + x(5,12) + x(5,13) + x(5,14) + x(5,15) + x(5,16)
+ + x(5,17) <= 1
+ r_6: + x(6,9) <= 1
+ r_7: + x(7,10) <= 1
+ r_8: + x(8,10) + x(8,11) <= 1
+ r_9: + x(6,9) + x(4,9) + x(1,9) <= 1
+ r_10: + x(8,10) + x(7,10) + x(2,10) + x(1,10) <= 1
+ r_11: + x(8,11) + x(5,11) + x(3,11) <= 1
+ r_12: + x(5,12) + x(4,12) + x(2,12) + x(1,12) <= 1
+ r_13: + x(5,13) + x(3,13) + x(2,13) <= 1
+ r_14: + x(5,14) + x(4,14) <= 1
+ r_15: + x(5,15) <= 1
+ r_16: + x(5,16) <= 1
+ r_17: + x(5,17) <= 1
+
+Bounds
+ 0 <= x(1,12) <= 1
+ 0 <= x(1,10) <= 1
+ 0 <= x(1,9) <= 1
+ 0 <= x(2,13) <= 1
+ 0 <= x(2,12) <= 1
+ 0 <= x(2,10) <= 1
+ 0 <= x(3,13) <= 1
+ 0 <= x(3,11) <= 1
+ 0 <= x(4,14) <= 1
+ 0 <= x(4,12) <= 1
+ 0 <= x(4,9) <= 1
+ 0 <= x(5,17) <= 1
+ 0 <= x(5,16) <= 1
+ 0 <= x(5,15) <= 1
+ 0 <= x(5,14) <= 1
+ 0 <= x(5,13) <= 1
+ 0 <= x(5,12) <= 1
+ 0 <= x(5,11) <= 1
+ 0 <= x(6,9) <= 1
+ 0 <= x(7,10) <= 1
+ 0 <= x(8,11) <= 1
+ 0 <= x(8,10) <= 1
+
+End
+\end{verbatim}
+\end{footnotesize}
+
+\subsection{glp\_asnprob\_okalg---solve assignment problem with
+out-of-kilter algorithm}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_asnprob_okalg(int form, glp_graph *G, int v_set,
+      int a_cost, double *sol, int a_x);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_mincost_okalg| finds optimal solution to the
+assignment problem with the out-of-kilter
+algorithm.\footnote{GLPK implementation of the out-of-kilter algorithm
+is based on the following book: L.~R.~Ford,~Jr., and D.~R.~Fulkerson,
+``Flows in Networks,'' The RAND Corp., Report R-375-PR (August 1962),
+Chap. III ``Minimal Cost Flow Problems,'' pp.~113-26.} Note that this
+routine requires all the problem data to be integer-valued.
+
+The parameter \verb|form| defines which LP formulation should be used:
+
+\verb|GLP_ASN_MIN| --- perfect matching (15)---(18), minimization;
+
+\verb|GLP_ASN_MAX| --- perfect matching (15)---(18), maximization;
+
+\verb|GLP_ASN_MMP| --- maximum weighted matching (11)---(14).
+
+The parameter \verb|G| is the graph program object, which specifies the
+assignment problem instance.
+
+The parameter \verb|v_set| specifies an offset of the field of type
+\verb|int| in the vertex data block, which contains the node set
+indicator:
+
+0 --- the node is in set $R$;
+
+1 --- the node is in set $S$.
+
+\newpage
+
+\noindent
+If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
+is in set $R$, and a node having no outgoing arcs is in set $S$.
+
+The parameter \verb|a_cost| specifies an offset of the field of type
+\verb|double| in the arc data block, which contains $c_{ij}$, the edge
+cost. This value must be integer in the range [\verb|-INT_MAX|,
+\verb|+INT_MAX|]. If \verb|a_cost| $<0$, it is assumed that $c_{ij}=1$
+for all edges.
+
+The parameter \verb|sol| specifies a location, to which the routine
+stores the objective value (that is, the total cost) found.
+If \verb|sol| is \verb|NULL|, the objective value is not stored.
+
+The parameter \verb|a_x| specifies an offset of the field of type
+\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
+If \verb|a_x| $<0$, this value is not stored.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & Optimal solution found.\\
+\verb|GLP_ENOPFS| & No (primal) feasible solution exists.\\
+\verb|GLP_EDATA| & Unable to start the search, because the assignment
+problem data are either incorrect (this error is detected by the
+routine \verb|glp_check_asnprob|), not integer-valued or out of range.\\
+\verb|GLP_ERANGE| & The search was prematurely terminated because of
+integer overflow.\\
+\verb|GLP_EFAIL| & An error has been detected in the program logic.
+(If this code is returned for your problem instance, please report to
+\verb|<bug-glpk@gnu.org>|.)\\
+\end{tabular}
+
+\subsubsection*{Comments}
+
+Since the out-of-kilter algorithm is designed to find a minimal cost
+circulation, the routine \verb|glp_asnprob_okalg| converts the original
+graph to a network suitable for this algorithm in the following
+way:\footnote{The conversion is performed internally and does not change
+the original graph program object passed to the routine.}
+
+1) it replaces each edge $(i,j)$ by arc $(i\rightarrow j)$,
+flow $x_{ij}$ through which has zero lower bound ($l_{ij}=0$), unity
+upper bound ($u_{ij}=1$), and per-unit cost $+c_{ij}$ (in case of
+\verb|GLP_ASN_MIN|), or $-c_{ij}$ (in case of \verb|GLP_ASN_MAX| and
+\verb|GLP_ASN_MMP|);
+
+2) then it adds one auxiliary feedback node $k$;
+
+\newpage
+
+3) for each original node $i\in R$ the routine adds auxiliary supply
+arc $(k\rightarrow i)$, flow $x_{ki}$ through which is costless
+($c_{ki}=0$) and either fixed at 1 ($l_{ki}=u_{ki}=1$, in case of
+\verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound and
+unity upper bound ($l_{ij}=0$, $u_{ij}=1$, in case of
+\verb|GLP_ASN_MMP|);
+
+4) similarly, for each original node $j\in S$ the routine adds
+auxiliary demand arc $(j\rightarrow k)$, flow $x_{jk}$ through which is
+costless ($c_{jk}=0$) and either fixed at 1 ($l_{jk}=u_{jk}=1$, in case
+of \verb|GLP_ASN_MIN| and \verb|GLP_ASN_MAX|) or has zero lower bound
+and unity upper bound ($l_{jk}=0$, $u_{jk}=1$, in case of
+\verb|GLP_ASN_MMP|).
+
+\subsubsection*{Example}
+
+The example program shown below reads the assignment problem instance
+in DIMACS format from file `\verb|sample.asn|', solves it by using the
+routine \verb|glp_asnprob_okalg|, and writes the solution found to the
+standard output.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { int set; } v_data;
+typedef struct { double cost; int x; } e_data;
+
+#define node(v) ((v_data *)((v)->data))
+#define edge(e) ((e_data *)((e)->data))
+
+int main(void)
+{     glp_graph *G;
+      glp_vertex *v;
+      glp_arc *e;
+      int i, ret;
+      double sol;
+      G = glp_create_graph(sizeof(v_data), sizeof(e_data));
+      glp_read_asnprob(G, offsetof(v_data, set),
+         offsetof(e_data, cost), "sample.asn");
+      ret = glp_asnprob_okalg(GLP_ASN_MMP, G,
+         offsetof(v_data, set), offsetof(e_data, cost), &sol,
+         offsetof(e_data, x));
+      printf("ret = %d; sol = %5g\n", ret, sol);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (e = v->out; e != NULL; e = e->t_next)
+            printf("edge %2d %2d: x = %d; c = %g\n",
+               e->tail->i, e->head->i, edge(e)->x, edge(e)->cost);
+      }
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+If `\verb|sample.asn|' is the example data file from the subsection
+describing the routine \verb|glp_read_asnprob|, the output may look
+like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading assignment problem data from `sample.asn'...
+Assignment problem has 8 + 9 = 17 nodes and 22 arcs
+38 lines were read
+ret = 0; sol =   180
+edge  1 12: x = 1; c = 20
+edge  1 10: x = 0; c = 21
+edge  1  9: x = 0; c = 13
+edge  2 13: x = 1; c = 26
+edge  2 12: x = 0; c = 8
+edge  2 10: x = 0; c = 12
+edge  3 13: x = 0; c = 11
+edge  3 11: x = 1; c = 22
+edge  4 14: x = 1; c = 25
+edge  4 12: x = 0; c = 36
+edge  4  9: x = 0; c = 12
+edge  5 17: x = 0; c = 32
+edge  5 16: x = 1; c = 35
+edge  5 15: x = 0; c = 8
+edge  5 14: x = 0; c = 4
+edge  5 13: x = 0; c = 11
+edge  5 12: x = 0; c = 40
+edge  5 11: x = 0; c = 41
+edge  6  9: x = 1; c = 13
+edge  7 10: x = 0; c = 19
+edge  8 11: x = 0; c = 15
+edge  8 10: x = 1; c = 39
+\end{verbatim}
+\end{footnotesize}
+
+\newpage
+
+\subsection{glp\_asnprob\_hall---find bipartite matching of maximum
+cardinality}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
+\end{verbatim}
+
+\subsubsection*{Description}
+
+The routine \verb|glp_asnprob_hall| finds a matching of maximal
+cardinality in the specified bipartite graph. It uses a version of the
+Fortran routine \verb|MC21A| developed by
+I.~S.~Duff\footnote{I.~S.~Duff, Algorithm 575: Permutations for
+zero-free diagonal, ACM Trans. on Math. Softw. 7 (1981), pp.~387-390.},
+which implements Hall's algorithm.\footnote{M.~Hall, ``An Algorithm for
+Distinct Representatives,'' Am. Math. Monthly 63 (1956), pp.~716-717.}
+
+The parameter \verb|G| is a pointer to the graph program object.
+
+The parameter \verb|v_set| specifies an offset of the field of type
+\verb|int| in the vertex data block, which contains the node set
+indicator:
+
+0 --- the node is in set $R$;
+
+1 --- the node is in set $S$.
+
+\noindent
+If \verb|v_set| $<0$, it is assumed that a node having no incoming arcs
+is in set $R$, and a node having no outgoing arcs is in set $S$.
+
+The parameter \verb|a_x| specifies an offset of the field of type
+\verb|int| in the arc data block, to which the routine stores $x_{ij}$.
+If \verb|a_x| $<0$, this value is not stored.
+
+\subsubsection*{Returns}
+
+The routine \verb|glp_asnprob_hall| returns the cardinality of the
+matching found. However, if the specified graph is incorrect (as
+detected by the routine \verb|glp_check_asnprob|), this routine returns
+a negative value.
+
+\subsubsection*{Comments}
+
+The same solution may be obtained with the routine
+\verb|glp_asnprob_okalg| (for LP formulation \verb|GLP_ASN_MMP| and
+all edge costs equal to 1). However, the routine \verb|glp_asnprob_hall|
+is much faster.
+
+\newpage
+
+\subsubsection*{Example}
+
+The example program shown below reads the assignment problem instance
+in DIMACS format from file `\verb|sample.asn|', finds a bipartite
+matching of maximal cardinality by using the routine
+\verb|glp_asnprob_hall|, and writes the solution found to the standard
+output.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { int set; } v_data;
+typedef struct { int x;   } e_data;
+
+#define node(v) ((v_data *)((v)->data))
+#define edge(e) ((e_data *)((e)->data))
+
+int main(void)
+{     glp_graph *G;
+      glp_vertex *v;
+      glp_arc *e;
+      int i, card;
+      G = glp_create_graph(sizeof(v_data), sizeof(e_data));
+      glp_read_asnprob(G, offsetof(v_data, set), -1,
+         "sample.asn");
+      card = glp_asnprob_hall(G, offsetof(v_data, set),
+         offsetof(e_data, x));
+      printf("card = %d\n", card);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (e = v->out; e != NULL; e = e->t_next)
+            printf("edge %2d %2d: x = %d\n",
+               e->tail->i, e->head->i, edge(e)->x);
+      }
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+If `\verb|sample.asn|' is the example data file from the subsection
+describing the routine \verb|glp_read_asnprob|, the output may look
+like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading assignment problem data from `sample.asn'...
+Assignment problem has 8 + 9 = 17 nodes and 22 arcs
+38 lines were read
+card = 7
+edge  1 12: x = 1
+edge  1 10: x = 0
+edge  1  9: x = 0
+edge  2 13: x = 1
+edge  2 12: x = 0
+edge  2 10: x = 0
+edge  3 13: x = 0
+edge  3 11: x = 1
+edge  4 14: x = 1
+edge  4 12: x = 0
+edge  4  9: x = 0
+edge  5 17: x = 1
+edge  5 16: x = 0
+edge  5 15: x = 0
+edge  5 14: x = 0
+edge  5 13: x = 0
+edge  5 12: x = 0
+edge  5 11: x = 0
+edge  6  9: x = 1
+edge  7 10: x = 1
+edge  8 11: x = 0
+edge  8 10: x = 0
+\end{verbatim}
+\end{footnotesize}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newpage
+
+\section{Critical path problem}
+
+\subsection{Background}
+
+The {\it critical path problem} (CPP) is stated as follows. Let there
+be given a project $J$, which a set of jobs (tasks, activities, etc.).
+Performing each job $i\in J$ requires time $t_i\geq 0$. Besides, over
+the set $J$ there is given a precedence relation $R\subseteq J\times J$,
+where $(i,j)\in R$ means that job $i$ immediately precedes job $j$, i.e.
+performing job $j$ cannot start until job $i$ has been completely
+performed. The problem is to find starting times $x_i$ for each job
+$i\in J$, which satisfy to the precedence relation and minimize the
+total duration (makespan) of the project.
+
+The following is an example of the critical path problem:
+
+\begin{center}
+\begin{tabular}{|c|l|c|c|}
+\hline
+Job&Desription&Time&Predecessors\\
+\hline
+A&Excavate&3&---\\
+B&Lay foundation&4&A\\
+C&Rough plumbing&3&B\\
+D&Frame&10&B\\
+E&Finish exterior&8&D\\
+F&Install HVAC&4&D\\
+G&Rough electric&6&D\\
+H&Sheet rock&8&C, E, F, G\\
+I&Install cabinets&5&H\\
+J&Paint&5&H\\
+K&Final plumbing&4&I\\
+L&Final electric&2&J\\
+M&Install flooring&4&K, L\\
+\hline
+\end{tabular}
+\end{center}
+
+Obviously, the project along with the precedence relation can be
+represented as a directed graph $G=(J,R)$ called {\it project network},
+where each node $i\in J$ corresponds to a job, and arc
+$(i\rightarrow j)\in R$ means that job $i$ immediately precedes job
+$j$.\footnote{There exists another network representation of the
+critical path problem, where jobs correspond to arcs while nodes
+correspond to events introduced to express the precedence relation.
+That representation, however, is much less convenient than the one,
+where jobs are represented as nodes of the network.} The project network
+for the example above is shown on Fig.~4.
+
+May note that the project network must be acyclic; otherwise, it would
+be impossible to satisfy to the precedence relation for any job that
+belongs to a cycle.
+
+\newpage
+
+\xymatrix
+{&&&C|3\ar[rd]&&I|5\ar[r]&K|4\ar[rd]&\\
+A|3\ar[r]&B|4\ar[rru]\ar[rd]&&E|8\ar[r]&H|8\ar[ru]\ar[rd]&&&M|4\\
+&&D|10\ar[ru]\ar[r]\ar[rd]&F|4\ar[ru]&&J|5\ar[r]&L|2\ar[ru]&\\
+&&&G|6\ar[ruu]&&&&\\
+}
+
+\bigskip
+
+\noindent\hfil
+Fig.~4. An example of the project network.
+
+\bigskip
+
+The critical path problem can be naturally formulated as the following
+LP problem:
+
+\medskip
+
+\noindent
+\hspace{.5in}minimize
+$$z\eqno(19)$$
+\hspace{.5in}subject to
+$$x_i+t_i\leq z\ \ \ \hbox{for all}\ i\in J\ \ \ \ \eqno(20)$$
+$$x_i+t_i\leq x_j\ \ \ \hbox{for all}\ (i,j)\in R\eqno(21)$$
+$$x_i\geq 0\ \ \ \ \ \ \ \hbox{for all}\ i\in J\ \ \eqno(22)$$
+
+The inequality constraints (21), which are active in the optimal
+solution, define so called {\it critical path} having the following
+property: the minimal project duration $z$ can be decreased only by
+decreasing the times $t_j$ for jobs on the critical path, and delaying
+any critical job delays the entire project.
+
+\subsection{glp\_cpp---solve critical path problem}
+
+\subsubsection{Synopsis}
+
+\begin{verbatim}
+double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
+\end{verbatim}
+
+\subsubsection{Description}
+
+The routine \verb|glp_cpp| solves the critical path problem represented
+in the form of the project network.
+
+The parameter \verb|G| is a pointer to the graph object, which
+specifies the project network. This graph must be acyclic. Multiple
+arcs are allowed being considered as single arcs.
+
+The parameter \verb|v_t| specifies an offset of the field of type
+\verb|double| in the vertex data block, which contains time $t_i\geq 0$
+needed to perform corresponding job $j\in J$. If \verb|v_t| $<0$, it is
+assumed that $t_i=1$ for all jobs.
+
+The parameter \verb|v_es| specifies an offset of the field of type
+\verb|double| in the vertex data block, to which the routine stores
+the {\it earliest start time} for corresponding job. If \verb|v_es|
+$<0$, this time is not stored.
+
+The parameter \verb|v_ls| specifies an offset of the field of type
+\verb|double| in the vertex data block, to which the routine stores
+the {\it latest start time} for corresponding job. If \verb|v_ls|
+$<0$, this time is not stored.
+
+The difference between the latest and earliest start times of some job
+is called its {\it time reserve}. Delaying a job within its time reserve
+does not affect the project duration, so if the time reserve is zero,
+the corresponding job is critical.
+
+\subsubsection{Returns}
+
+The routine \verb|glp_cpp| returns the minimal project duration, i.e.
+minimal time needed to perform all jobs in the project.
+
+\subsubsection{Example}
+
+The example program below solves the critical path problem shown on
+Fig.~4 by using the routine \verb|glp_cpp| and writes the solution found
+to the standard output.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { double t, es, ls; } v_data;
+
+#define node(v) ((v_data *)((v)->data))
+
+int main(void)
+{     glp_graph *G;
+      int i;
+      double t, es, ef, ls, lf, total;
+      G = glp_create_graph(sizeof(v_data), 0);
+      glp_add_vertices(G, 13);
+      node(G->v[1])->t = 3;   /* A: Excavate */
+      node(G->v[2])->t = 4;   /* B: Lay foundation */
+      node(G->v[3])->t = 3;   /* C: Rough plumbing */
+      node(G->v[4])->t = 10;  /* D: Frame */
+      node(G->v[5])->t = 8;   /* E: Finish exterior */
+      node(G->v[6])->t = 4;   /* F: Install HVAC */
+      node(G->v[7])->t = 6;   /* G: Rough elecrtic */
+      node(G->v[8])->t = 8;   /* H: Sheet rock */
+      node(G->v[9])->t = 5;   /* I: Install cabinets */
+      node(G->v[10])->t = 5;  /* J: Paint */
+      node(G->v[11])->t = 4;  /* K: Final plumbing */
+      node(G->v[12])->t = 2;  /* L: Final electric */
+      node(G->v[13])->t = 4;  /* M: Install flooring */
+      glp_add_arc(G, 1, 2);   /* A precedes B */
+      glp_add_arc(G, 2, 3);   /* B precedes C */
+      glp_add_arc(G, 2, 4);   /* B precedes D */
+      glp_add_arc(G, 4, 5);   /* D precedes E */
+      glp_add_arc(G, 4, 6);   /* D precedes F */
+      glp_add_arc(G, 4, 7);   /* D precedes G */
+      glp_add_arc(G, 3, 8);   /* C precedes H */
+      glp_add_arc(G, 5, 8);   /* E precedes H */
+      glp_add_arc(G, 6, 8);   /* F precedes H */
+      glp_add_arc(G, 7, 8);   /* G precedes H */
+      glp_add_arc(G, 8, 9);   /* H precedes I */
+      glp_add_arc(G, 8, 10);  /* H precedes J */
+      glp_add_arc(G, 9, 11);  /* I precedes K */
+      glp_add_arc(G, 10, 12); /* J precedes L */
+      glp_add_arc(G, 11, 13); /* K precedes M */
+      glp_add_arc(G, 12, 13); /* L precedes M */
+      total = glp_cpp(G, offsetof(v_data, t), offsetof(v_data, es),
+         offsetof(v_data, ls));
+      printf("Minimal project duration is %.2f\n\n", total);
+      printf("Job  Time      ES     EF     LS     LF\n");
+      printf("--- ------   ------ ------ ------ ------\n");
+      for (i = 1; i <= G->nv; i++)
+      {  t = node(G->v[i])->t;
+         es = node(G->v[i])->es;
+         ef = es + node(G->v[i])->t;
+         ls = node(G->v[i])->ls;
+         lf = ls + node(G->v[i])->t;
+         printf("%3d %6.2f %s %6.2f %6.2f %6.2f %6.2f\n",
+            i, t, ls - es < 0.001 ? "*" : " ", es, ef, ls, lf);
+      }
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+The output from the example program shown below includes job number,
+the time needed to perform a job, earliest start time (\verb|ES|),
+earliest finish time (\verb|EF|), latest start time (\verb|LS|), and
+latest finish time (\verb|LF|) for each job in the project. Critical
+jobs are marked by asterisks.
+
+\newpage
+
+\begin{footnotesize}
+\begin{verbatim}
+Minimal project duration is 46.00
+
+Job  Time      ES     EF     LS     LF
+--- ------   ------ ------ ------ ------
+  1   3.00 *   0.00   3.00   0.00   3.00
+  2   4.00 *   3.00   7.00   3.00   7.00
+  3   3.00     7.00  10.00  22.00  25.00
+  4  10.00 *   7.00  17.00   7.00  17.00
+  5   8.00 *  17.00  25.00  17.00  25.00
+  6   4.00    17.00  21.00  21.00  25.00
+  7   6.00    17.00  23.00  19.00  25.00
+  8   8.00 *  25.00  33.00  25.00  33.00
+  9   5.00 *  33.00  38.00  33.00  38.00
+ 10   5.00    33.00  38.00  35.00  40.00
+ 11   4.00 *  38.00  42.00  38.00  42.00
+ 12   2.00    38.00  40.00  40.00  42.00
+ 13   4.00 *  42.00  46.00  42.00  46.00
+\end{verbatim}
+\end{footnotesize}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\chapter{Graph Optimization API Routines}
+
+\section{Maximum clique problem}
+
+\subsection{Background}
+
+The {\it maximum clique problem (MCP)} is a classic combinatorial
+optimization problem. Given an undirected graph $G=(V,E)$, where $V$ is
+a set of vertices, and $E$ is a set of edges, this problem is to find
+the largest {\it clique} $C\subseteq G$, i.e. the largest induced
+complete subgraph. A generalization of this problem is the {\it maximum
+weight clique problem (MWCP)}, which is to find a clique $C\subseteq G$
+of the largest weight $\displaystyle\sum_{v\in C}w(v)\rightarrow\max$,
+where $w(v)$ is a weight of vertex $v\in V$.
+
+An example of the maximum weight clique problem is shown on Fig.~5.
+
+\begin{figure}
+\noindent\hfil
+\begin{tabular}{c}
+{\xymatrix %@C=16pt
+{&&&{v_1}\ar@{-}[lllddd]\ar@{-}[llddddd]\ar@{-}[dddddd]
+\ar@{-}[rrrddd]&&&\\
+&{v_2}\ar@{-}[rrrr]\ar@{-}[rrrrdddd]\ar@{-}[rrddddd]\ar@{-}[dddd]&&&&
+{v_3}\ar@{-}[llllldd]\ar@{-}[lllldddd]\ar@{-}[dddd]&\\
+&&&&&&\\
+{v_4}\ar@{-}[rrrrrr]\ar@{-}[rrrddd]&&&&&&{v_5}\ar@{-}[lllddd]
+\ar@{-}[ldd]\\
+&&&&&&\\
+&{v_6}\ar@{-}[rrrr]&&&&{v_7}&\\
+&&&{v_8}&&&\\
+}}
+\end{tabular}
+\begin{tabular}{r@{\ }c@{\ }l}
+$w(v_1)$&=&3\\$w(v_2)$&=&4\\$w(v_3)$&=&8\\$w(v_4)$&=&1\\
+$w(v_5)$&=&5\\$w(v_6)$&=&2\\$w(v_7)$&=&1\\$w(v_8)$&=&3\\
+\end{tabular}
+
+\begin{center}
+Fig.~5. An example of the maximum weight clique problem.
+\end{center}
+\end{figure}
+
+\subsection{glp\_wclique\_exact---find maximum weight clique with exact
+algorithm}
+
+\subsubsection*{Synopsis}
+
+\begin{verbatim}
+int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol,
+      int v_set);
+\end{verbatim}
+
+\subsection*{Description}
+
+The routine {\it glp\_wclique\_exact} finds a maximum weight clique in
+the specified undirected graph with the exact algorithm developed by
+Patric \"Osterg{\aa}rd.\footnote{P.~R.~J.~\"Osterg{\aa}rd, A new
+algorithm for the maximum-weight clique problem, Nordic J. of Computing,
+Vol.~8, No.~4, 2001, pp.~424--36.}
+
+The parameter $G$ is the program object, which specifies an undirected
+graph. Each arc $(x\rightarrow y)$ in $G$ is considered as edge
+$(x,y)$, self-loops are ignored, and multiple edges, if present, are
+replaced (internally) by simple edges.
+
+The parameter {\it v\_wgt} specifies an offset of the field of type
+{\bf double} in the vertex data block, which contains a weight of
+corresponding vertex. Vertex weights must be integer-valued in the
+range $[0,$ {\it INT\_MAX}$]$. If {\it v\_wgt} $<0$, it is assumed that
+all vertices of the graph have the weight 1.
+
+The parameter {\it sol} specifies a location, to which the routine
+stores the weight of the clique found (the clique weight is the sum
+of weights of all vertices included in the clique.) If {\it sol} is
+{\it NULL}, the solution is not stored.
+
+The parameter {\it v\_set} specifies an offset of the field of type
+{\bf int} in the vertex data block, to which the routines stores a
+vertex flag: 1 means that the corresponding vertex is included in the
+clique found, and 0 otherwise. If {\it v\_set} $<0$, vertex flags are
+not stored.
+
+\subsubsection*{Returns}
+
+\def\arraystretch{1}
+
+\begin{tabular}{@{}p{25mm}p{97.3mm}@{}}
+0 & Optimal solution found.\\
+\verb|GLP_EDATA| & Unable to start the search, because some vertex
+weights are either not integer-valued or out of range. This code is
+also returned if the sum of weights of all vertices exceeds
+{\it INT\_MAX}. \\
+\end{tabular}
+
+\subsubsection*{Notes}
+
+\noindent\indent
+1. The routine {\it glp\_wclique\_exact} finds exact solution. Since
+both MCP and MWCP problems are NP-complete, the algorithm may require
+exponential time in worst cases.
+
+2. Internally the specified graph is converted to an adjacency matrix
+in {\it dense} format. This requires about $|V|^2/16$ bytes of memory,
+where $|V|$ is the number of vertices in the graph.
+
+\subsubsection*{Example}
+
+The example program shown below reads a MWCP instance in DIMACS
+clique/coloring format from file `\verb|sample.clq|', finds the clique
+of largest weight, and writes the solution found to the standard output.
+
+\begin{footnotesize}
+\begin{verbatim}
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+typedef struct { double wgt; int set; } v_data;
+
+#define vertex(v) ((v_data *)((v)->data))
+
+int main(void)
+{     glp_graph *G;
+      glp_vertex *v;
+      int i, ret;
+      double sol;
+      G = glp_create_graph(sizeof(v_data), 0);
+      glp_read_ccdata(G, offsetof(v_data, wgt), "sample.clq");
+      ret = glp_wclique_exact(G, offsetof(v_data, wgt), &sol,
+         offsetof(v_data, set));
+      printf("ret = %d; sol = %g\n", ret, sol);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         printf("vertex %d: weight = %g, flag = %d\n",
+            i, vertex(v)->wgt, vertex(v)->set);
+      }
+      glp_delete_graph(G);
+      return 0;
+}
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+For the example shown on Fig.~5 the data file may look like follows:
+
+\begin{footnotesize}
+\begin{verbatim}
+c sample.clq
+c
+c This is an example of the maximum weight clique
+c problem in DIMACS clique/coloring format.
+c
+p edge 8 16
+n 1 3
+n 2 4
+n 3 8
+n 5 5
+n 6 2
+n 8 3
+e 1 4
+e 1 5
+e 1 6
+e 1 8
+e 2 3
+e 2 6
+e 2 7
+e 2 8
+e 3 4
+e 3 6
+e 3 7
+e 4 5
+e 4 8
+e 5 7
+e 5 8
+e 6 7
+c
+c eof
+\end{verbatim}
+\end{footnotesize}
+
+\noindent
+The corresponding output from the example program is the following:
+
+\begin{footnotesize}
+\begin{verbatim}
+Reading graph from `sample.clq'...
+Graph has 8 vertices and 16 edges
+28 lines were read
+ret = 0; sol = 15
+vertex 1: weight = 3, flag = 0
+vertex 2: weight = 4, flag = 1
+vertex 3: weight = 8, flag = 1
+vertex 4: weight = 1, flag = 0
+vertex 5: weight = 5, flag = 0
+vertex 6: weight = 2, flag = 1
+vertex 7: weight = 1, flag = 1
+vertex 8: weight = 3, flag = 0
+\end{verbatim}
+\end{footnotesize}
+
+\end{document}
Index: deps/glpk/doc/miplib2.txt
===================================================================
--- deps/glpk/doc/miplib2.txt	(revision 9)
+++ deps/glpk/doc/miplib2.txt	(revision 9)
@@ -0,0 +1,135 @@
+Solver:   GLPSOL 4.40 (options used: --pcost)
+Computer: Intel Pentium 4, 3.0 GHz
+Platform: Cygwin 1.5.25
+Compiler: GCC 3.4.4 (options used: -O3)
+Test set: MIPLIB 2.0 <http://miplib.zib.de/miplib3/miplib/>
+
+Problem  Optimal Solution Cuts Used    Nodes  Iters Time,s Mem,MB
+-------- ---------------- --------- -------- ------ ------ ------
+air01    +6.796000000e+03                  3     41    < 1    1.2
+air02    +7.810000000e+03                 43    201      6   13.8
+air03    +3.401600000e+05                 33    414     12   21.0
+air04    +5.613700000e+04               1901 109800    396   32.4
+air05    +2.637400000e+04               6445 201649    452   45.0
+air06    +4.964900000e+04                 11   6868     31   18.1
+bell3a   +8.784303160e+05 --gomory      7965  42363     17    6.1
+bell3b   +1.178616062e+07 --gomory      6031  30467     19    3.2
+bell4    +1.854148420e+07 --gomory      7203  25019     16    2.9
+bell5    +8.966406492e+06 --gomory      5605  18555      8    1.5
+bm23     +3.400000000e+01                373    878    < 1    0.2
+cracpb1  +2.219900000e+04                 47   5258      2    1.3
+dcmulti  +1.881820000e+05                743   3366      2    1.1
+diamond        infeasible                  3      4    < 1    0.1
+dsbmip   -3.051981750e+02 --mir          217  46088     24    4.5
+egout    +5.681007000e+02                 91    137    < 1    0.3
+enigma   +0.000000000e+00              16419  55071      6    3.2
+fixnet3  +5.197300000e+04                 81    380    < 1    1.4
+fixnet4  +8.936000000e+03                211   1095      1    1.4
+fixnet6  +3.983000000e+03               1031   3136      2    1.7
+flugpl   +1.201500000e+06                397    231    < 1    0.1
+gen      +1.123133627e+05                195   3991      1    1.7
+khb05250 +1.069402260e+08               2163  14498      5    2.8
+l152lav  +4.722000000e+03               7419  95299     68   12.0
+lp4l     +2.967000000e+03                173   1331      2    1.7
+lseu     +1.120000000e+03              10821  31954      5    2.5
+misc01   +5.635000000e+02                769   4593      1    0.5
+misc02   +1.690000000e+03                 29    282    < 1    0.2
+misc03   +3.360000000e+03                957   6742      2    1.1
+misc04   +2.666699247e+03                 17   2052      1    7.0
+misc05   +2.984500000e+03                293   2520      1    1.1
+misc06   +1.285086074e+04                 57    941    < 1    2.7
+misc07   +2.810000000e+03 --mir        66075 579129    424   33.4
+mod008   +3.070000000e+02               8185  24245      8    2.3
+mod010   +6.548000000e+03                315   6283      7    5.3
+mod011
+mod013   +2.809500000e+02                545   1155    < 1    0.3
+modglob  +2.074050809e+07 --mir         5197  31985     20    2.8
+noswot
+p0033    +3.089000000e+03                305    955    < 1    0.2
+p0040    +6.202700000e+04                 17     66    < 1    0.1
+p0201    +7.615000000e+03                521   3660      1    0.9
+p0282    +2.584110000e+05                623   1204      1    0.8
+p0291    +5.223749000e+03                 71    154    < 1    0.7
+p0548    +8.691000000e+03               7617  23556      9    2.9
+p2756    +3.124000000e+03 --mir         3911  15157     57   10.9
+p6000    -2.451377000e+06              19209  40906    570   15.8
+pipex    +7.882630000e+02               1569   2469    < 1    0.4
+qiu      -1.328731369e+02              80473 1918742  1174   69.2
+rentacar +3.035676098e+07                 43   1649      3   12.1
+rgn      +8.219999924e+01               3325  18700      2    1.2
+sample2  +3.750000000e+02                163    347    < 1    0.2
+sentoy   -7.772000000e+03                335    723    < 1    0.4
+set1al   +1.586975000e+04 --mir           17    532    < 1    1.5
+set1ch
+set1cl   +6.484250000e+03 --mir            1    502    < 1    1.1
+stein15  +9.000000000e+00                 87    375    < 1    0.2
+stein27  +1.800000000e+01               3255  15327      2    1.0
+stein45  +3.000000000e+01              52301 389140    139   19.2
+stein9   +5.000000000e+00                 17     45    < 1    0.1
+vpm1     +2.000000000e+01 --mir            9    836    < 1    0.9
+
+PROBLEM CHARACTERISTICS
+
+Problem    Rows   Cols (   Int    0/1)   Nonz    Best Solution
+-------- ------ ---------------------- ------ --------------------------
+air01        24    771 (   all    all)   4986             6796 (opt)
+air02        51   6774 (   all    all)  68329             7810 (opt)
+air03       125  10757 (   all    all) 101785           340160 (opt)
+air04       824   8904 (   all    all)  81869            56138 (opt)
+air05       427   7195 (   all    all)  59316            26402 (not opt)
+air06       826   8627 (   all    all)  79433            49649 (opt)
+bell3a      124    133 (    71     39)    441        878430.32 (opt)
+bell3b      124    133 (    71     39)    441      11786160.62 (opt)
+bell4       106    117 (    64     34)    385      18541484.20 (opt)
+bell5        92    104 (    58     30)    340       8966406.49 (opt)
+bm23         21     27 (   all    all)    505               34 (opt)
+cracpb1     144    572 (   all    all)   4730            22199 (opt)
+dcmulti     291    548 (    75    all)   1833      188182.0000 (opt)
+diamond       5      2 (   all    all)      9     integer infeasible
+dsbmip     1855   1886 (   192    160)   9768         -305.198 (opt)
+egout        99    141 (    55    all)    392          568.101 (opt)
+enigma       22    100 (   all    all)    298              0.0 (opt)
+fixnet3     479    878 (   378    all)   2631            51973 (opt)
+fixnet4     479    878 (   378    all)   2621             8936 (opt)
+fixnet6     479    878 (   378    all)   2550             3983 (opt)
+flugpl       19     18 (    11   none)     64          1201500 (opt)
+gen         781    870 (   150    144)   3174           112313 (opt)
+khb05250    102   1350 (    24    all)   3973        106940226 (opt)
+l152lav      98   1989 (   all    all)  11911             4750 (not opt)
+lp4l         86   1086 (   all    all)   5763             2967 (opt)
+lseu         29     89 (   all    all)    394             1120 (opt)
+misc01       55     83 (    82    all)    746            563.5 (opt)
+misc02       40     59 (    58    all)    414             1690 (opt)
+misc03       97    160 (   159    all)   2054             3360 (opt)
+misc04     1726   4897 (    30    all)  17253         2666.699 (opt)
+misc05      301    136 (    74    all)   2946           2984.5 (opt)
+misc06      821   1808 (   112    all)   5860       12850.8607 (opt)
+misc07      213    260 (   259    all)   8620             2810 (not opt)
+mod008        7    319 (   all    all)   1562              307 (opt)
+mod010      147   2655 (   all    all)  13858             6548 (opt)
+mod011     4482  10958 (    96    all)  37425        -54558535 (opt)
+mod013       63     96 (    48    all)    288           280.95 (opt)
+modglob     292    422 (    98    all)   1390         20740508 (opt)
+noswot      183    128 (   100     75)    760              -43 (opt)
+p0033        17     33 (   all    all)    131             3089 (opt)
+p0040        24     40 (   all    all)    150            62027 (opt)
+p0201       134    201 (   all    all)   2124             7615 (opt)
+p0282       242    282 (   all    all)   2248           258411 (opt)
+p0291       253    291 (   all    all)    349        5223.7490 (opt)
+p0548       177    548 (   all    all)   2127             8691 (opt)
+p2756       756   2756 (   all    all)  11103             3124 (opt)
+p6000      2177   6000 (   all    all)  54238         -2451377 (opt)
+pipex        26     48 (   all    all)    240          788.263 (opt)
+qiu        1193    840 (    48    all)   3432      -132.873137 (opt)
+rentacar   6804   9557 (    55    all)  42019         30356761 (opt)
+rgn          25    180 (   100    all)    540          82.1999 (opt)
+sample2      46     67 (    21    all)    179              375 (opt)
+sentoy       31     60 (   all    all)   1860            -7772 (opt)
+set1al      493    712 (   240    all)   1884          15869.7 (opt)
+set1ch      493    712 (   240    all)   1884          54537.7 (opt)
+set1cl      493    712 (   240    all)   1884          6484.25 (opt)
+stein15      37     15 (   all    all)    135                9 (opt)
+stein27     119     27 (   all    all)    405               18 (opt)
+stein45     332     45 (   all    all)   1079               30 (opt)
+stein9       14      9 (   all    all)     54                5 (opt)
+vpm1        235    378 (   168    all)    917               20 (opt)
Index: deps/glpk/doc/miplib3.txt
===================================================================
--- deps/glpk/doc/miplib3.txt	(revision 9)
+++ deps/glpk/doc/miplib3.txt	(revision 9)
@@ -0,0 +1,143 @@
+Solver:   GLPSOL 4.40 
+Computer: Intel Pentium 4, 3.0 GHz
+Platform: Cygwin 1.5.25
+Compiler: GCC 3.4.4 (options used: -O3)
+Test set: MIPLIB 3.0 <http://miplib.zib.de/miplib3/miplib.html>
+
+Problem  Optimal Solution Options Used        Nodes  Iters Time,s Mem,MB
+-------- ---------------- ---------------- -------- ------ ------ ------
+10teams  +9.240000000e+02 --pcost --gomory     6013 349276    207   12.7
+air03    +3.401600000e+05 --pcost                33    414     12   21.0
+air04    +5.613700000e+04 --pcost              1901 109800    396   32.4
+air05    +2.637400000e+04 --pcost              6445 201649    452   45.0
+arki001
+bell3a   +8.784303160e+05 --pcost --gomory     7965  42363     17    6.1
+bell5    +8.966406492e+06 --pcost --gomory     5605  18555      8    1.5
+blend2   +7.598985000e+00 --pcost              7185  24256      7    2.1
+cap6000  -2.451377000e+06 --pcost             19209  40906    569   15.8
+dano3mip 
+danoint
+dcmulti  +1.881820000e+05 --pcost               743   3366      2    1.1
+dsbmip   -3.051981750e+02 --pcost --mir         217  46088     24    4.5
+egout    +5.681007000e+02 --pcost                91    137    < 1    0.3
+enigma   +0.000000000e+00 --pcost             16419  55071      6    3.2
+fast0507
+fiber    +4.059351800e+05 --pcost --mir         407   3108      4    2.4
+fixnet6  +3.983000000e+03 --pcost              1031   3136      2    1.7
+flugpl   +1.201500000e+06 --pcost               397    231    < 1    0.1
+gen      +1.123133627e+05 --pcost               195   3991      1    1.7
+gesa2    +2.577985637e+07 --pcost --mir          59   2723      4    4.1
+gesa2_o  +2.577985637e+07 --pcost --mir          69   2588      5    3.7
+gesa3    +2.799104265e+07 --pcost --mir          93   2774      5    3.7
+gesa3_o  +2.799104265e+07 --pcost --mir         117   3271      6    3.6
+gt2      +2.116600000e+04 --pcost              5613  26115      2    1.2
+harp2
+khb05250 +1.069402260e+08 --pcost              2163  14498      5    2.8
+l152lav  +4.722000000e+03 --pcost              7419  95299     68   12.0
+lseu     +1.120000000e+03 --pcost             10821  31954      5    2.5
+marksh1
+marksh2
+mas74
+mas76
+misc03   +3.360000000e+03 --pcost               957   6742      2    1.1
+misc06   +1.285086074e+04 --pcost                57    941    < 1    2.7
+misc07   +2.810000000e+03 --pcost --mir       66075 579129    424   33.4
+mitre
+mkc
+mod008   +3.070000000e+02 --pcost              8185  24245      8    2.3
+mod010   +6.548000000e+03 --pcost               315   6283      7    5.3
+mod011
+modglob  +2.074050809e+07 --pcost --mir        5197  31985     20    2.8
+noswot
+nw04     +1.686200000e+04 (none)                361   5544    345  138.3
+p0033    +3.089000000e+03 --pcost               305    955    < 1    0.2
+p0201    +7.615000000e+03 --pcost               521   3660      1    0.9
+p0282    +2.584110000e+05 --pcost               623   1204      1    0.8
+p0548    +8.691000000e+03 --pcost              7617  23556      9    2.9
+p2756    +3.124000000e+03 --pcost --mir        3911  15157     57   10.9
+pk1
+pp08a    +7.350000000e+03 --pcost --mir         663   9196      4    1.3
+pp08acut +7.350000000e+03 --pcost --mir       17233 260160    154   21.1
+qiu      -1.328731369e+02 --pcost             80473 1918742  1174   69.2
+qnet1    +1.602969268e+04 --pcost --mir         183  20352     16    3.6
+qnet1_o  +1.602969268e+04 --pcost --mir          75   7645      9    3.3
+rentacar +3.035676098e+07 --pcost                43   1649      3   12.1
+rgn      +8.219999924e+01 --pcost              3325  18700      2    1.2
+rout
+set1ch
+seymour
+stein27  +1.800000000e+01 --pcost              3255  15327      2    1.0
+stein45  +3.000000000e+01 --pcost             52301 389140    139   19.2
+swath
+vpm1     +2.000000000e+01 --pcost --mir           9    836    < 1    0.9
+vpm2     +1.375000000e+01 --pcost --mir       11729 164856     91    9.2
+
+PROBLEM CHARACTERISTICS
+
+Problem    Rows   Cols (   Int    0/1)   Nonz    Best Solution
+-------- ------ ---------------------- ------ --------------------------
+10teams     230   2025 (  1800    all)  12150              924 (opt)
+air03       125  10757 (   all    all) 101785           340160 (opt)
+air04       824   8904 (   all    all)  81869            56138 (opt)
+air05       427   7195 (   all    all)  59316            26402 (not opt)
+arki001    1048   1388 (   538    415)  20439     7580813.0459 (not opt)
+bell3a      124    133 (    71     39)    441        878430.32 (opt)
+bell5        92    104 (    58     30)    340       8966406.49 (opt)
+blend2      274    353 (   264    231)   1409         7.598985 (opt)
+cap6000    2176   6000 (   all    all)  48249         -2451377 (opt)
+dano3mip   3202  13873 (   552    all)  79655         728.1111 (not opt)
+danoint     664    521 (    56    all)   3232            65.67 (opt)
+dcmulti     291    548 (    75    all)   1833      188182.0000 (opt)
+dsbmip     1855   1886 (   192    160)   9768         -305.198 (opt)
+egout        99    141 (    55    all)    392          568.101 (opt)
+enigma       22    100 (   all    all)    298              0.0 (opt)
+fast0507    507  63009 (   all    all) 409439              174 (opt)
+fiber       363   1298 (  1254    all)   2944     405935.18000 (opt)
+fixnet6     479    878 (   378    all)   2550             3983 (opt)
+flugpl       19     18 (    11   none)     64          1201500 (opt)
+gen         781    870 (   150    144)   3174           112313 (opt)
+gesa2      1392   1224 (   408    240)   5064     25779856.372 (opt)
+gesa2_o    1248   1224 (   720    384)   3672     25779856.372 (opt)
+gesa3      1368   1152 (   384    216)   4944     27991042.648 (opt)
+gesa3_o    1224   1152 (   672    336)   3624     27991042.648 (opt)
+gt2          29    188 (   all     24)    376        21166.000 (opt)
+harp2       112   2993 (   all    all)   5840     -73899798.00 (opt)
+khb05250    102   1350 (    24    all)   3973        106940226 (opt)
+l152lav      98   1989 (   all    all)  11911             4750 (not opt)
+lseu         29     89 (   all    all)    394             1120 (opt)
+marksh1       7     62 (    50    all)    324
+marksh2       8     74 (    60    all)    448
+mas74        13    151 (   150    all)   1705       11801.1857 (opt)
+mas76        12    151 (   150    all)   1639       40005.0541 (opt)
+misc03       97    160 (   159    all)   2054             3360 (opt)
+misc06      821   1808 (   112    all)   5860       12850.8607 (opt)
+misc07      213    260 (   259    all)   8620             2810 (not opt)
+mitre      2054  10724 (   all    all)  39704           115155 (opt)
+mkc        3412   5325 (  5323    all)  20621
+mod008        7    319 (   all    all)   1562              307 (opt)
+mod010      147   2655 (   all    all)  13858             6548 (opt)
+mod011     4482  10958 (    96    all)  37425        -54558535 (opt)
+modglob     292    422 (    98    all)   1390         20740508 (opt)
+noswot      183    128 (   100     75)    760              -43 (opt)
+nw04         36  87482 (   all    all) 636666            16862 (opt)
+p0033        17     33 (   all    all)    131             3089 (opt)
+p0201       134    201 (   all    all)   2124             7615 (opt)
+p0282       242    282 (   all    all)   2248           258411 (opt)
+p0548       177    548 (   all    all)   2127             8691 (opt)
+p2756       756   2756 (   all    all)  11103             3124 (opt)
+pk1          45     86 (    55    all)    915               11 (opt)
+pp08a       136    240 (    64    all)    480             7350 (opt)
+pp08acut    246    240 (    64    all)    839             7350 (opt)
+qiu        1193    840 (    48    all)   3432      -132.873137 (opt)
+qnet1       503   1541 (  1417   1288)   4622     16029.692681 (opt)
+qnet1_o     456   1541 (  1417   1288)   4214     16029.692681 (opt)
+rentacar   6804   9557 (    55    all)  42019         30356761 (opt)
+rgn          25    180 (   100    all)    540          82.1999 (opt)
+rout        291    556 (   315    300)   2431          1077.56 (opt)
+set1ch      493    712 (   240    all)   1884          54537.7 (opt)
+seymour    4944   1372 (   all    all)  33549          423 (not opt)
+stein27     119     27 (   all    all)    405               18 (opt)
+stein45     332     45 (   all    all)   1079               30 (opt)
+swath       885   6805 (  6724    all)  34966
+vpm1        235    378 (   168    all)    917               20 (opt)
+vpm2        234    378 (   168    all)    917            13.75 (opt)
Index: deps/glpk/doc/netlib.txt
===================================================================
--- deps/glpk/doc/netlib.txt	(revision 9)
+++ deps/glpk/doc/netlib.txt	(revision 9)
@@ -0,0 +1,103 @@
+Solver:   GLPSOL 4.40 (default options used)
+Computer: Intel Pentium 4, 3.0 GHz
+Platform: Cygwin 1.5.25
+Compiler: GCC 3.4.4 (options used: -O3)
+Test set: Netlib LP collection <ftp://ftp.netlib.org/lp/data/>
+
+Problem    Rows   Cols   Nonz       Optimum        Iters  Time,s  Mem,MB
+--------  -----  -----  ------  ----------------  ------  ------  ------
+25fv47      822   1571   11127  +5.501845888e+03    1651     < 1     2.1
+80bau3b    2263   9799   29063  +9.872241924e+05    5358       3     6.4
+adlittle     57     97     465  +2.254949632e+05      71     < 1     0.1   
+afiro        28     32      88  -4.647531429e+02      10     < 1     0.1
+agg         489    163    2541  -3.599176729e+07     100     < 1     0.5
+agg2        517    302    4515  -2.023925236e+07     178     < 1     0.8
+agg3        517    302    4531  +1.031211594e+07     182     < 1     0.8
+bandm       306    472    2659  -1.586280185e+02     252     < 1     0.6
+beaconfd    174    262    3476  +3.359248581e+04      61     < 1     0.4
+blend        75     83     521  -3.081214985e+01      41     < 1     0.1
+bnl1        644   1175    6129  +1.977629562e+03     581     < 1     1.4
+bnl2       2325   3489   16124  +1.811236540e+03    1730       1     3.7
+boeing1     351    384    3865  -3.352135675e+02     419     < 1     0.7
+boeing2     167    143    1339  -3.150187280e+02     161     < 1     0.3
+bore3d      234    315    1525  +1.373080394e+03      38     < 1     0.3
+brandy      221    249    2150  +1.518509896e+03     191     < 1     0.5
+capri       272    353    1786  +2.690012914e+03     203     < 1     0.4
+cycle      1904   2857   21322  -5.226393025e+00     953     < 1     3.5
+czprob      930   3523   14173  +2.185196699e+06     754     < 1     2.6
+d2q06c     2172   5167   35674  +1.227842108e+05    5368       7     6.2
+d6cube      416   6184   43888  +3.154916667e+02    6596       6     6.0
+degen2      445    534    4449  -1.435178000e+03     506     < 1     1.0
+degen3     1504   1818   26230  -9.872940000e+02    2205       2     4.1
+dfl001     6072  12230   41873  +1.126639605e+07   39863     117    11.0
+e226        224    282    2767  -2.586492907e+01     206     < 1     0.5
+etamacro    401    688    2489  -7.557152333e+02     444     < 1     0.7
+fffff800    525    854    6235  +5.556795648e+05     167     < 1     1.0
+finnis      498    614    2714  +1.727910656e+05     338     < 1     0.6
+fit1d        25   1026   14430  -9.146378092e+03     488     < 1     1.7
+fit1p       628   1677   10894  +9.146378092e+03    1379     < 1     1.9
+fit2d        26  10500  138018  -6.846429329e+04    5751      16    15.8
+fit2p      3001  13525   60784  +6.846429329e+04   11960      17    11.3
+forplan     162    421    4916  -6.642189613e+02     170     < 1     0.7
+ganges     1310   1681    7021  -1.095857361e+05     724     < 1     1.9
+gfrd-pnc    617   1092    3467  +6.902236000e+06     416     < 1     1.0
+greenbea   2393   5405   31499  -7.255524813e+07    3012       3     5.8
+greenbeb   2393   5405   31499  -4.302260261e+06    2153       2     5.8
+grow15      301    645    5665  -1.068709413e+08     358     < 1     1.1
+grow22      441    946    8318  -1.608343365e+08     606     < 1     1.6
+grow7       141    301    2633  -4.778781181e+07     159     < 1     0.5
+israel      175    142    2358  -8.966448219e+05     123     < 1     0.4
+kb2          44     41     291  -1.749900130e+03      38     < 1     0.1
+lotfi       154    308    1086  -2.526470606e+01     104     < 1     0.3
+maros       847   1443   10006  -5.806374370e+04     703     < 1     1.8
+maros-r7   3137   9408  151120  +1.497185166e+06    2340       5    16.7
+modszk1     688   1620    4158  +3.206197291e+02     705     < 1     1.4
+nesm        663   2923   13988  +1.407603649e+07    2240       1     2.4
+perold      626   1376    6026  -9.380755278e+03    1103     < 1     1.5
+pilot      1442   3652   43220  -5.574831533e+02    5726      11     7.8
+pilot-ja    941   1988   14706  -6.113136466e+03    1697       1     2.5
+pilot-we    723   2789    9218  -2.720107533e+06    1382       1     2.3
+pilot4      411   1000    5145  -2.581139259e+03     532     < 1     1.3
+pilot87    2031   4883   73804  +3.017103744e+02    7573      28    12.2
+pilotnov    976   2172   13129  -4.497276188e+03     988       1     2.5
+recipe       92    180     752  -2.666160000e+02      17     < 1     0.2
+sc105       106    103     281  -5.220206121e+01      51     < 1     0.2
+sc205       206    203     552  -5.220206121e+01     124     < 1     0.3
+sc50a        51     48     131  -6.457507706e+01      25     < 1     0.1
+sc50b        51     48     119  -7.000000000e+01      30     < 1     0.1
+scagr25     472    500    2029  -1.475343306e+07     352     < 1     0.7
+scagr7      130    140     553  -2.331389824e+06      94     < 1     0.2
+scfxm1      331    457    2612  +1.841675903e+04     281     < 1     0.6
+scfxm2      661    914    5229  +3.666026156e+04     587     < 1     1.1
+scfxm3      991   1371    7846  +5.490125455e+04     881     < 1     1.7
+scorpion    389    358    1708  +1.878124823e+03     146     < 1     0.4
+scrs8       491   1169    4029  +9.042969538e+02     545     < 1     1.1
+scsd1        78    760    3148  +8.666666674e+00      91     < 1     0.6
+scsd6       148   1350    5666  +5.050000008e+01     182     < 1     1.0
+scsd8       398   2750   11334  +9.049999999e+02     397     < 1     2.1
+sctap1      301    480    2052  +1.412250000e+03     196     < 1     0.5
+sctap2     1091   1880    8124  +1.724807143e+03     425     < 1     1.7
+sctap3     1481   2480   10734  +1.424000000e+03     729     < 1     2.4
+seba        516   1028    4874  +1.571160000e+04     883     < 1     1.0
+share1b     118    225    1182  -7.658931858e+04     167     < 1     0.3
+share2b      97     79     730  -4.157322407e+02      87     < 1     0.2
+shell       537   1775    4900  +1.208825346e+09     467     < 1     1.2
+ship04l     403   2118    8450  +1.793324538e+06     373     < 1     1.5
+ship04s     403   1458    5810  +1.798714700e+06     262     < 1     1.0
+ship08l     779   4283   17085  +1.909055211e+06     516     < 1     2.9
+ship08s     779   2387    9501  +1.920098211e+06     274     < 1     1.7
+ship12l    1152   5427   21597  +1.470187919e+06     686     < 1     3.7
+ship12s    1152   2763   10941  +1.489236134e+06     383     < 1     2.0
+sierra     1228   2036    9252  +1.539436218e+07     857     < 1     2.1
+stair       357    467    3857  -2.512669512e+02     399     < 1     1.0
+standata    360   1075    3038  +1.257699500e+03     140     < 1     0.7
+standgub    362   1184    3147  +1.257699500e+03     140     < 1     0.8
+standmps    468   1075    3686  +1.406017500e+03     299     < 1     0.9
+stocfor1    118    111     474  -4.113197622e+04      24     < 1     0.2
+stocfor2   2158   2031    9492  -3.902440854e+04     499     < 1     2.6
+stocfor3  16676  15695   74004  -3.997678394e+04    4456      11    19.7
+truss      1001   8806   36642  +4.588158472e+05    4744       4     6.5
+tuff        334    587    4523  +2.921477651e-01      61     < 1     0.8
+vtp-base    199    203     914  +1.298314625e+05      69     < 1     0.2
+wood1p      245   2594   70216  +1.442902412e+00     326     < 1     7.1
+woodw      1099   8405   37478  +1.304476333e+00    1093     < 1     6.0
Index: deps/glpk/examples/INDEX
===================================================================
--- deps/glpk/examples/INDEX	(revision 9)
+++ deps/glpk/examples/INDEX	(revision 9)
@@ -0,0 +1,52 @@
+assign.mod     Assignment problem
+bpp.mod        Bin packing problem
+cal.mod        Print an ASCII calendar of the given year
+cf12a.mod      Curve fitting problem
+cf12b.mod      Curve fitting problem
+cflsq.mod      Curve fitting problem by least squares
+color.mod      Graph coloring problem
+cpp.mod        Critical path problem
+crypto.mod     A crypto-arithmetic puzzle
+dea.mod        Data envelopment analysis (DEA)
+diet.mod       Stigler's nutrition model
+dist.mod       A product distribution model
+egypt.mod      A static model for fertilizer production
+fctp.mod       Fixed-charge transportation problem
+food.mod       Food manufacture model
+food2.mod      Food manufacture model
+gap.mod        Generalized assignment problem
+graph.mod      Graph visualization
+hashi.mod      A solver for the Japanese number-puzzle Hashiwokakero
+huge.mod       Arithmetic mean of a large number of integers
+jssp.mod       Job-shop scheduling problem
+magic.mod      Magic square
+maxcut.mod     Maximum cut problem
+maxflow.mod    Maximum flow problem
+mfasp.mod      Minimum feedback arc set problem
+mfvsp.mod      Minimum feedback vertex set problem
+min01ks.mod    Finding minimal equivalent 0-1 knapsack inequality
+misp.mod       Maximum independent set problem
+money.mod      A crypto-arithmetic puzzle
+mvcp.mod       Minimum vertex cover problem
+numbrix.mod    Number placement puzzle
+pbn/*.*        Paint-by-numbers puzzle
+plan.mod       A simple LP problem
+prod.mod       A multiperiod production model
+qfit.mod       Quadratic curve fitting solution
+queens.mod     A classic combinatorial optimization problem
+sat.mod        Satisfiability problem
+shiftcover.mod Workforce shift coverage assignment problem
+shikaku.mod    A solver for the logic puzzle Shikaku
+sorting.mod    How to sort arrays in MathProg
+spp.mod        Shortest path problem
+stigler.mod    Original Stigler's 1939 diet problem
+sudoku.mod     Number placement puzzle
+tas.mod        Tail assignment problem
+todd.mod       A class of hard instances of 0-1 knapsack problems
+train.mod      A model of railroad passenger car allocation
+transp.mod     A transportation problem
+trick.mod      A transportation design problem
+tsp.mod        Traveling salesman problem
+xyacfs.mod     Extended yet another curve fitting solution
+yacfs.mod      Yet another curve fitting solution
+zebra.mod      Who owns the zebra?
Index: deps/glpk/examples/Makefile.am
===================================================================
--- deps/glpk/examples/Makefile.am	(revision 9)
+++ deps/glpk/examples/Makefile.am	(revision 9)
@@ -0,0 +1,15 @@
+## Process this file with automake to produce Makefile.in ##
+
+INCLUDES = -I$(srcdir)/../src
+
+LDADD = ../src/libglpk.la
+
+bin_PROGRAMS = glpsol
+
+glpsol_SOURCES = glpsol.c
+
+check: glpsol$(EXEEXT)
+	./glpsol$(EXEEXT) --version
+	./glpsol$(EXEEXT) --mps $(srcdir)/plan.mps
+
+## eof ##
Index: deps/glpk/examples/Makefile.in
===================================================================
--- deps/glpk/examples/Makefile.in	(revision 9)
+++ deps/glpk/examples/Makefile.in	(revision 9)
@@ -0,0 +1,513 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = glpsol$(EXEEXT)
+subdir = examples
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_glpsol_OBJECTS = glpsol.$(OBJEXT)
+glpsol_OBJECTS = $(am_glpsol_OBJECTS)
+glpsol_LDADD = $(LDADD)
+glpsol_DEPENDENCIES = ../src/libglpk.la
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(glpsol_SOURCES)
+DIST_SOURCES = $(glpsol_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+to_host_path_cmd = @to_host_path_cmd@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(srcdir)/../src
+LDADD = ../src/libglpk.la
+glpsol_SOURCES = glpsol.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu examples/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu examples/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p || test -f $$p1; \
+	  then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' `; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+glpsol$(EXEEXT): $(glpsol_OBJECTS) $(glpsol_DEPENDENCIES) 
+	@rm -f glpsol$(EXEEXT)
+	$(LINK) $(glpsol_OBJECTS) $(glpsol_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpsol.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+	clean-generic clean-libtool ctags distclean distclean-compile \
+	distclean-generic distclean-libtool distclean-tags distdir dvi \
+	dvi-am html html-am info info-am install install-am \
+	install-binPROGRAMS install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am \
+	uninstall-binPROGRAMS
+
+
+check: glpsol$(EXEEXT)
+	./glpsol$(EXEEXT) --version
+	./glpsol$(EXEEXT) --mps $(srcdir)/plan.mps
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: deps/glpk/examples/assign.mod
===================================================================
--- deps/glpk/examples/assign.mod	(revision 9)
+++ deps/glpk/examples/assign.mod	(revision 9)
@@ -0,0 +1,77 @@
+/* ASSIGN, Assignment Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The assignment problem is one of the fundamental combinatorial
+   optimization problems.
+
+   In its most general form, the problem is as follows:
+
+   There are a number of agents and a number of tasks. Any agent can be
+   assigned to perform any task, incurring some cost that may vary
+   depending on the agent-task assignment. It is required to perform all
+   tasks by assigning exactly one agent to each task in such a way that
+   the total cost of the assignment is minimized.
+
+   (From Wikipedia, the free encyclopedia.) */
+
+param m, integer, > 0;
+/* number of agents */
+
+param n, integer, > 0;
+/* number of tasks */
+
+set I := 1..m;
+/* set of agents */
+
+set J := 1..n;
+/* set of tasks */
+
+param c{i in I, j in J}, >= 0;
+/* cost of allocating task j to agent i */
+
+var x{i in I, j in J}, >= 0;
+/* x[i,j] = 1 means task j is assigned to agent i
+   note that variables x[i,j] are binary, however, there is no need to
+   declare them so due to the totally unimodular constraint matrix */
+
+s.t. phi{i in I}: sum{j in J} x[i,j] <= 1;
+/* each agent can perform at most one task */
+
+s.t. psi{j in J}: sum{i in I} x[i,j] = 1;
+/* each task must be assigned exactly to one agent */
+
+minimize obj: sum{i in I, j in J} c[i,j] * x[i,j];
+/* the objective is to find a cheapest assignment */
+
+solve;
+
+printf "\n";
+printf "Agent  Task       Cost\n";
+printf{i in I} "%5d %5d %10g\n", i, sum{j in J} j * x[i,j],
+   sum{j in J} c[i,j] * x[i,j];
+printf "----------------------\n";
+printf "     Total: %10g\n", sum{i in I, j in J} c[i,j] * x[i,j];
+printf "\n";
+
+data;
+
+/* These data correspond to an example from [Christofides]. */
+
+/* Optimal solution is 76 */
+
+param m := 8;
+
+param n := 8;
+
+param c : 1  2  3  4  5  6  7  8 :=
+      1  13 21 20 12  8 26 22 11
+      2  12 36 25 41 40 11  4  8
+      3  35 32 13 36 26 21 13 37
+      4  34 54  7  8 12 22 11 40
+      5  21  6 45 18 24 34 12 48
+      6  42 19 39 15 14 16 28 46
+      7  16 34 38  3 34 40 22 24
+      8  26 20  5 17 45 31 37 43 ;
+
+end;
Index: deps/glpk/examples/bpp.mod
===================================================================
--- deps/glpk/examples/bpp.mod	(revision 9)
+++ deps/glpk/examples/bpp.mod	(revision 9)
@@ -0,0 +1,83 @@
+/* BPP, Bin Packing Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* Given a set of items I = {1,...,m} with weight w[i] > 0, the Bin
+   Packing Problem (BPP) is to pack the items into bins of capacity c
+   in such a way that the number of bins used is minimal. */
+
+param m, integer, > 0;
+/* number of items */
+
+set I := 1..m;
+/* set of items */
+
+param w{i in 1..m}, > 0;
+/* w[i] is weight of item i */
+
+param c, > 0;
+/* bin capacity */
+
+/* We need to estimate an upper bound of the number of bins sufficient
+   to contain all items. The number of items m can be used, however, it
+   is not a good idea. To obtain a more suitable estimation an easy
+   heuristic is used: we put items into a bin while it is possible, and
+   if the bin is full, we use another bin. The number of bins used in
+   this way gives us a more appropriate estimation. */
+
+param z{i in I, j in 1..m} :=
+/* z[i,j] = 1 if item i is in bin j, otherwise z[i,j] = 0 */
+
+   if i = 1 and j = 1 then 1
+   /* put item 1 into bin 1 */
+
+   else if exists{jj in 1..j-1} z[i,jj] then 0
+   /* if item i is already in some bin, do not put it into bin j */
+
+   else if sum{ii in 1..i-1} w[ii] * z[ii,j] + w[i] > c then 0
+   /* if item i does not fit into bin j, do not put it into bin j */
+
+   else 1;
+   /* otherwise put item i into bin j */
+
+check{i in I}: sum{j in 1..m} z[i,j] = 1;
+/* each item must be exactly in one bin */
+
+check{j in 1..m}: sum{i in I} w[i] * z[i,j] <= c;
+/* no bin must be overflowed */
+
+param n := sum{j in 1..m} if exists{i in I} z[i,j] then 1;
+/* determine the number of bins used by the heuristic; obviously it is
+   an upper bound of the optimal solution */
+
+display n;
+
+set J := 1..n;
+/* set of bins */
+
+var x{i in I, j in J}, binary;
+/* x[i,j] = 1 means item i is in bin j */
+
+var used{j in J}, binary;
+/* used[j] = 1 means bin j contains at least one item */
+
+s.t. one{i in I}: sum{j in J} x[i,j] = 1;
+/* each item must be exactly in one bin */
+
+s.t. lim{j in J}: sum{i in I} w[i] * x[i,j] <= c * used[j];
+/* if bin j is used, it must not be overflowed */
+
+minimize obj: sum{j in J} used[j];
+/* objective is to minimize the number of bins used */
+
+data;
+
+/* The optimal solution is 3 bins */
+
+param m := 6;
+
+param w := 1 50, 2 60, 3 30, 4 70, 5 50, 6 40;
+
+param c := 100;
+
+end;
Index: deps/glpk/examples/cal.mod
===================================================================
--- deps/glpk/examples/cal.mod	(revision 9)
+++ deps/glpk/examples/cal.mod	(revision 9)
@@ -0,0 +1,49 @@
+/* cal.mod - print an ASCII calendar of the given year */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+param year, integer, >= 0001, <= 3999, default 2010;
+
+param first_day{m in 1..12}, integer, >= 0, <= 6, :=
+      time2str(str2time(year & "-" & m & "-01", "%Y-%m-%d"), "%w");
+
+param days_in_month{m in 1..12}, integer, >= 28, <= 31, :=
+      (str2time(year + (if m < 12 then 0 else 1) & "-" &
+         (if m < 12 then m+1 else 1) & "-01", "%Y-%m-%d") -
+      str2time(year & "-" & m & "-01", "%Y-%m-%d")) / 86400;
+
+param foo{m in 1..12, k in 0..5, d in 0..6}, integer, :=
+      7 * k + d + 1 - first_day[m];
+
+param cal{m in 1..12, k in 0..5, d in 0..6}, integer, :=
+      if 1 <= foo[m,k,d] and foo[m,k,d] <= days_in_month[m] then
+         foo[m,k,d];
+
+printf "\n";
+printf "%33s%04d\n", "", year;
+printf "\n";
+for {t in 1..12 by 3}
+{     for {m in t..t+2}
+      {  printf "%7s%-14s", "", time2str(str2time(m, "%m"), "%B");
+         printf{0..0: m < t+2} "   ";
+      }
+      printf "\n";
+      for {m in t..t+2}
+      {  printf "  S  M Tu  W Th  F  S";
+         printf{0..0: m < t+2} "   ";
+      }
+      printf "\n";
+      for {k in 0..5}
+      {  for {m in t..t+2}
+         {  for {d in 0..6}
+            {  printf{0..0: cal[m,k,d]  = 0} "   ";
+               printf{0..0: cal[m,k,d] != 0} " %2d", cal[m,k,d];
+            }
+            printf{0..0: m < t+2} "   ";
+         }
+         printf "\n";
+      }
+}
+printf "\n";
+
+end;
Index: deps/glpk/examples/cf12a.mod
===================================================================
--- deps/glpk/examples/cf12a.mod	(revision 9)
+++ deps/glpk/examples/cf12a.mod	(revision 9)
@@ -0,0 +1,81 @@
+/*
+
+  Curve fitting problem 12.11(a) H P Williams "Model Building in Mathematical Programming"
+
+  Dr. H J Mackenzie
+  HARD software
+  hjm@hardsoftware.com
+
+  2006-01-05
+
+ */
+
+# set of points
+
+set I;
+
+# independent variable
+
+param x {i in I};
+
+# dependent variable
+
+param y {i in I};
+
+# output input values
+
+printf {i in I} "x = %.1f; y = %.1f\n", x[i], y[i];
+
+# define equation variables
+
+var a;
+
+var b;
+
+var u {i in I}, >= 0;
+
+var v {i in I}, >= 0;
+
+# define objective function
+
+minimize error: sum {i in I} u[i] + sum {i in I} v[i];
+
+# define equation constraint
+
+s.t. equation {i in I} : b * x[i] + a + u[i] - v[i] = y[i];
+
+solve;
+
+printf "y = %.4fx + %.4f\n", b, a;
+
+/*
+ *
+ * DATA section
+ *
+ */
+
+data;
+
+param : I :   x    y :=
+        1     0    1
+        2   0.5  0.9
+        3     1  0.7
+        4   1.5  1.5
+        5   1.9    2
+        6   2.5  2.4
+        7     3  3.2
+        8   3.5    2
+        9     4  2.7
+       10   4.5  3.5
+       11     5    1
+       12   5.5    4
+       13     6  3.6
+       14   6.6  2.7
+       15     7  5.7
+       16   7.6  4.6
+       17   8.5    6
+       18     9  6.8
+       19    10  7.3
+;
+
+end;
Index: deps/glpk/examples/cf12b.mod
===================================================================
--- deps/glpk/examples/cf12b.mod	(revision 9)
+++ deps/glpk/examples/cf12b.mod	(revision 9)
@@ -0,0 +1,88 @@
+/*
+
+  Curve fitting problem 12.11(b) H P Williams "Model Building in Mathematical Programming"
+
+  Dr. H J Mackenzie
+  HARD software
+  hjm@hardsoftware.com
+
+  2006-01-23
+
+ */
+
+# set of points
+
+set I;
+
+# independent variable
+
+param x {i in I};
+
+# dependent variable
+
+param y {i in I};
+
+# output input values
+
+printf {i in I} "x = %.1f; y = %.1f\n", x[i], y[i];
+
+# define equation variables
+
+var a;
+
+var b;
+
+var u {i in I}, >= 0;
+
+var v {i in I}, >= 0;
+
+var z;
+
+# define objective function
+
+minimize deviation: z;
+
+# define equation constraint
+
+s.t. equation {i in I} : b * x[i] + a + u[i] - v[i] = y[i];
+
+# define deviation constrains
+
+s.t. u_deviation {i in I} : z - u[i] >= 0;
+s.t. v_deviation {i in I} : z - v[i] >= 0;
+
+solve;
+
+printf "y = %.4fx + %.4f Max deviation = %.4f\n", b, a, z;
+
+/*
+ *
+ * DATA section
+ *
+ */
+
+data;
+
+param : I :   x    y :=
+        1     0    1
+        2   0.5  0.9
+        3     1  0.7
+        4   1.5  1.5
+        5   1.9    2
+        6   2.5  2.4
+        7     3  3.2
+        8   3.5    2
+        9     4  2.7
+       10   4.5  3.5
+       11     5    1
+       12   5.5    4
+       13     6  3.6
+       14   6.6  2.7
+       15     7  5.7
+       16   7.6  4.6
+       17   8.5    6
+       18     9  6.8
+       19    10  7.3
+;
+
+end;
Index: deps/glpk/examples/cflsq.mod
===================================================================
--- deps/glpk/examples/cflsq.mod	(revision 9)
+++ deps/glpk/examples/cflsq.mod	(revision 9)
@@ -0,0 +1,51 @@
+/*Curve fitting problem by Least Squares
+  Nigel_Galloway@operamail.com
+  October 1st., 2007
+*/
+set Sample;
+param Sx {z in Sample};
+param Sy {z in Sample};
+
+var X;
+var Y;
+var Ex{z in Sample};
+var Ey{z in Sample};
+
+/* sum of variances is zero for Sx*/
+variencesX{z in Sample}: X + Ex[z] = Sx[z];
+zumVariancesX: sum{z in Sample} Ex[z] = 0;
+/* sum of variances is zero for Sy*/
+variencesY{z in Sample}: Y + Ey[z] = Sy[z];
+zumVariancesY: sum{z in Sample} Ey[z] = 0;
+
+solve;
+
+param b1 := (sum{z in Sample} Ex[z]*Ey[z])/(sum{z in Sample} Ex[z]*Ex[z]);
+printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", Y-b1*X, if b1 < 0 then "-" else "+", abs(b1);
+
+data;
+
+param:
+Sample:   Sx    Sy :=
+  1         0    1
+  2       0.5  0.9
+  3         1  0.7
+  4       1.5  1.5
+  5       1.9    2
+  6       2.5  2.4
+  7         3  3.2
+  8       3.5    2
+  9         4  2.7
+ 10       4.5  3.5
+ 11         5    1
+ 12       5.5    4
+ 13         6  3.6
+ 14       6.6  2.7
+ 15         7  5.7
+ 16       7.6  4.6
+ 17       8.5    6
+ 18         9  6.8
+ 19        10  7.3
+;
+
+end;
Index: deps/glpk/examples/color.mod
===================================================================
--- deps/glpk/examples/color.mod	(revision 9)
+++ deps/glpk/examples/color.mod	(revision 9)
@@ -0,0 +1,113 @@
+/* COLOR, Graph Coloring Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* Given an undirected loopless graph G = (V, E), where V is a set of
+   nodes, E <= V x V is a set of arcs, the Graph Coloring Problem is to
+   find a mapping (coloring) F: V -> C, where C = {1, 2, ... } is a set
+   of colors whose cardinality is as small as possible, such that
+   F(i) != F(j) for every arc (i,j) in E, that is adjacent nodes must
+   be assigned different colors. */
+
+param n, integer, >= 2;
+/* number of nodes */
+
+set V := {1..n};
+/* set of nodes */
+
+set E, within V cross V;
+/* set of arcs */
+
+check{(i,j) in E}: i != j;
+/* there must be no loops */
+
+/* We need to estimate an upper bound of the number of colors |C|.
+   The number of nodes |V| can be used, however, for sparse graphs such
+   bound is not very good. To obtain a more suitable estimation we use
+   an easy "greedy" heuristic. Let nodes 1, ..., i-1 are already
+   assigned some colors. To assign a color to node i we see if there is
+   an existing color not used for coloring nodes adjacent to node i. If
+   so, we use this color, otherwise we introduce a new color. */
+
+set EE := setof{(i,j) in E} (i,j) union setof{(i,j) in E} (j,i);
+/* symmetrisized set of arcs */
+
+param z{i in V, case in 0..1} :=
+/* z[i,0] = color index assigned to node i
+   z[i,1] = maximal color index used for nodes 1, 2, ..., i-1 which are
+            adjacent to node i */
+(  if case = 0 then
+   (  /* compute z[i,0] */
+      min{c in 1..z[i,1]}
+      (  if not exists{j in V: j < i and (i,j) in EE} z[j,0] = c then
+            c
+         else
+            z[i,1] + 1
+      )
+   )
+   else
+   (  /* compute z[i,1] */
+      if not exists{j in V: j < i} (i,j) in EE then
+         1
+      else
+         max{j in V: j < i and (i,j) in EE} z[j,0]
+   )
+);
+
+check{(i,j) in E}: z[i,0] != z[j,0];
+/* check that all adjacent nodes are assigned distinct colors */
+
+param nc := max{i in V} z[i,0];
+/* number of colors used by the heuristic; obviously, it is an upper
+   bound of the optimal solution */
+
+display nc;
+
+var x{i in V, c in 1..nc}, binary;
+/* x[i,c] = 1 means that node i is assigned color c */
+
+var u{c in 1..nc}, binary;
+/* u[c] = 1 means that color c is used, i.e. assigned to some node */
+
+s.t. map{i in V}: sum{c in 1..nc} x[i,c] = 1;
+/* each node must be assigned exactly one color */
+
+s.t. arc{(i,j) in E, c in 1..nc}: x[i,c] + x[j,c] <= u[c];
+/* adjacent nodes cannot be assigned the same color */
+
+minimize obj: sum{c in 1..nc} u[c];
+/* objective is to minimize the number of colors used */
+
+data;
+
+/* These data correspond to the instance myciel3.col from:
+   http://mat.gsia.cmu.edu/COLOR/instances.html */
+
+/* The optimal solution is 4 */
+
+param n := 11;
+
+set E :=
+ 1 2
+ 1 4
+ 1 7
+ 1 9
+ 2 3
+ 2 6
+ 2 8
+ 3 5
+ 3 7
+ 3 10
+ 4 5
+ 4 6
+ 4 10
+ 5 8
+ 5 9
+ 6 11
+ 7 11
+ 8 11
+ 9 11
+ 10 11
+;
+
+end;
Index: deps/glpk/examples/cplex/README
===================================================================
--- deps/glpk/examples/cplex/README	(revision 9)
+++ deps/glpk/examples/cplex/README	(revision 9)
@@ -0,0 +1,44 @@
+The program module in this subdirectory is a crude implementation of
+CPLEX-like interface to GLPK API. It consists of two files: cplex.c and
+cplex.h.
+
+NOTE that this module is NOT a clean room implementation of the CPLEX
+callable library. It only implements a CPLEX-like interface to the GLPK
+API routines, and its main purpose is to provide possibility to build
+and run applications which normally use the CPLEX callable library.
+
+This module approximately corresponds to CPLEX 9.0.
+
+Currently this module can be used as a linear programming solver for
+Concorde, the state-of-the-art computer code for solving the symmetric
+traveling salesman problem (TSP) developed by David Applegate, Robert
+Bixby, Vasek Chvatal, and William Cook. For details about Concorde see
+its web page at http://www.tsp.gatech.edu/concorde.html.
+
+To build Concorde along with GLPK you need to do the following:
+
+1. Configure, build, and install GLPK.
+
+2. Download the Concorde tarball co031219.tgz (version Dec 19, 2003),
+   unpack and unarchive it.
+
+3. Copy files cplex.h and cplex.c to subdirectory concorde/LP/.
+
+4. Create file named lpglpk.c in subdirectory concorde/LP/. This file
+   must contain the following two lines:
+
+      #include "cplex.c"
+      #include "lpcplex8.c"
+
+5. Configure Concorde in usual way (./configure) and then build it with
+   the following command:
+
+      make CPPFLAGS=-I. LPSOLVER_INTERFACE=lpglpk.c LPSOLVER_LIB=-lglpk
+
+   The Concorde executable can be found in subdirectory concorde/TSP/.
+
+Please note that currently this GLPK interface module does not support
+some important features (namely, CPXgetijdiv, CPXmdleave, CPXpivotin,
+CPXpivotout, and CPXstrongbranch), so large (more than 1000 nodes) TSP
+instances cannot be solved in a reasonable time, and some instances may
+cause abnormal termination of Concorde (if CPXgetijdiv is called).
Index: deps/glpk/examples/cplex/concorde.txt
===================================================================
--- deps/glpk/examples/cplex/concorde.txt	(revision 9)
+++ deps/glpk/examples/cplex/concorde.txt	(revision 9)
@@ -0,0 +1,121 @@
+Solver:     Concorde-03.12.19 (options used: -s 99)
+            http://www.tsp.gatech.edu/concorde.html
+LP Solver:  GLPK 4.34 (CPLEX-like interface module examples/cplex)
+Computer:   Intel Pentium 4 CPU 3GHz, 2GB of RAM
+Platform:   Cygwin 1.5.24 (Windows XP 5.1 Build 2600 Service Pack 4)
+Compiler:   GCC 3.4.4 (options used: -O2)
+Test set:   http://www.iwr.uni-heidelberg.de/groups/comopt/software/
+            TSPLIB95/
+
+Problem     Solution   B&B   Time, s
+---------   --------   ---   -------
+a280            2579     1      3.09
+ali535        202339     1     21.88
+att48          10628     1      0.20
+att532         27686     7     74.31
+bayg29          1610     1      0.08
+bays29          2020     1      0.08
+berlin52        7542     1      0.11
+bier127       118282     1      0.62
+brazil58       25395     1      0.23
+brd14051
+brg180          1950     1      0.34
+burma14         3323     1      0.06
+ch130           6110     1      0.92
+ch150           6528     1      1.69
+d1291
+d15112
+d1655
+d18512
+d198           15780     3      4.92
+d2103
+d493           35002     5    123.89
+d657           48913    11    148.17
+dantzig42        699     1      0.08
+dsj1000     18660188    13    251.00
+eil101                                 (failed due to CPXgetijdiv)
+eil51            426     1      0.17
+eil76            538     1      0.11
+fl1400
+fl1577
+fl3795
+fl417          11861     1     47.20
+fnl4461
+fri26            937     1      0.05
+gil262          2378     3     10.39
+gr120           6942     1      0.66
+gr137          69853     1      2.09
+gr17            2085     1      0.03
+gr202          40160     1      3.97
+gr21            2707     1      0.03
+gr229         134602     7     19.45
+gr24            1272     1      0.03
+gr431         171414     9     40.67
+gr48            5046     1      0.22
+gr666         294358     3     40.23
+gr96           55209     1      1.22
+hk48           11461     1      0.08
+kroA100        21282     1      0.41
+kroA150        26524     1      2.09
+kroA200        29368     1      2.44
+kroB100        22141     1      1.20
+kroB150        26130     1      1.66
+kroB200        29437     1      1.41
+kroC100        20749     1      0.42
+kroD100        21294     1      0.50
+kroE100        22068     1      0.94
+lin105         14379     1      0.23
+lin318         42029     1      4.28
+nrw1379
+p654           34643     1     17.08
+pa561           2763    15    370.70
+pcb1173        56892    11    370.30
+pcb3038
+pcb442         59778    13     35.86
+pla33810
+pla7397
+pla85900
+pr1002        259045     1     23.08
+pr107          44303     1      0.38
+pr124          59030     1      1.23
+pr136          96772     1      2.19
+pr144          58537     1      0.89
+pr152          73682     1      2.73
+pr226          80369     1      2.72
+pr2392
+pr264          49135     1      1.61
+pr299          48191     3     14.52
+pr439         107217    15    117.75
+pr76          108159     1      0.95
+rat195          2323     5     12.91
+rat575          6773    19    202.52
+rat783          8806     1     37.92
+rat99           1211     1      0.50
+rd100           7910     1      0.28
+rd400          15281    11     74.41
+rl11849
+rl1304
+rl1323
+rl1889
+rl5915
+rl5934
+si1032         92650     1     82.09
+si175          21407     3      8.97
+si535          48450     1     71.28
+st70             675     1      0.20
+swiss42         1273     1      0.06
+ts225         126643     1     21.25
+tsp225          3916     1     10.14
+u1060         224094    13    507.44
+u1432
+u159           42080     1      0.41
+u1817
+u2152
+u2319
+u574           36905     1     32.84
+u724           41910    19    238.42
+ulysses16       6859     1      0.19
+ulysses22       7013     1      0.47
+usa13509
+vm1084        239297     9    543.38
+vm1748
Index: deps/glpk/examples/cplex/cplex.c
===================================================================
--- deps/glpk/examples/cplex/cplex.c	(revision 9)
+++ deps/glpk/examples/cplex/cplex.c	(revision 9)
@@ -0,0 +1,2130 @@
+/* cplex.c (CPLEX-like interface to GLPK API) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glpk.h>
+#include "cplex.h"
+
+struct CPXENV
+{     /* environment block */
+      CPXLP *list;
+      /* linked list of problem objects */
+      int *intparam; /* int intparam[]; */
+      /* integer control parameters */
+      double *dblparam; /* double dblparam[]; */
+      /* floating-point control parameters */
+};
+
+struct CPXLP
+{     /* problem object */
+      CPXENV *env;
+      /* pointer to environment block */
+      glp_prob *prob;
+      /* pointer to underlying GLPK problem object */
+      int rflen;
+      /* length of the array rflag */
+      char *rflag; /* char rflag[rflen]; */
+      /* rflag[i], i = 0,...,nrows-1, is a flag of i-th row: */
+#define RF_NOT_RANGED   0  /* not ranged */
+#define RF_RANGED_POS   1  /* ranged, RHS = lower bound */
+#define RF_RANGED_NEG   2  /* ranged, RHS = upper bound */
+      int stat;
+      /* solution status reported by CPXgetstat; zero means no solution
+         exists */
+      int meth;
+      /* method indicator reported by CPXgetmethod */
+      int iwlen;
+      /* length of the working array */
+      int *iwork; /* int iwork[iwlen] */
+      /* working array initialized by binary zeros */
+      CPXLP *link;
+      /* pointer to another problem object */
+};
+
+struct intparam
+{     int which;
+      int defv;
+      int minv;
+      int maxv;
+};
+
+struct dblparam
+{     int which;
+      double defv;
+      double minv;
+      double maxv;
+};
+
+struct errstring
+{     int code;
+      const char *string;
+};
+
+#define BIGINT 2100000000
+#define BIGDBL 1e75
+
+static const struct intparam intparam[] =
+{     {CPX_PARAM_ADVIND, 0, 0, 2},
+      {CPX_PARAM_AGGIND, -1, -1, BIGINT},
+      {CPX_PARAM_DATACHECK, CPX_OFF, CPX_OFF, CPX_ON},
+      {CPX_PARAM_DPRIIND, CPX_DPRIIND_AUTO, CPX_DPRIIND_AUTO,
+         CPX_DPRIIND_DEVEX},
+      {CPX_PARAM_FASTMIP, CPX_OFF, CPX_OFF, CPX_ON}, /* ??? */
+      {CPX_PARAM_ITLIM, BIGINT, 0, BIGINT},
+      {CPX_PARAM_PERIND, CPX_OFF, CPX_OFF, CPX_ON},
+      {CPX_PARAM_PPRIIND, CPX_PPRIIND_AUTO, CPX_PPRIIND_PARTIAL,
+         CPX_PPRIIND_FULL},
+      {CPX_PARAM_PREIND, CPX_ON, CPX_OFF, CPX_ON},
+      {CPX_PARAM_REINV, 0, 0, 10000},
+      {CPX_PARAM_SCRIND, CPX_OFF, CPX_OFF, CPX_ON},
+      {CPX_PARAM_SIMDISPLAY, 1, 0, 2},
+};
+
+static const struct dblparam dblparam[] =
+{     {CPX_PARAM_EPOPT, 1e-6, 1e-9, 1e-1},
+      {CPX_PARAM_EPPER, 1e-6, 1e-8, BIGDBL},
+      {CPX_PARAM_EPRHS, 1e-6, 1e-9, 1e-1},
+      {CPX_PARAM_OBJLLIM, -BIGDBL, -BIGDBL, +BIGDBL},
+      {CPX_PARAM_OBJULIM, +BIGDBL, -BIGDBL, +BIGDBL},
+};
+
+static const struct errstring errstring[] =
+{     {CPXERR_ARRAY_NOT_ASCENDING, "Array entry %d not ascending"},
+      {CPXERR_BAD_ARGUMENT, "Invalid argument"},
+      {CPXERR_BAD_CTYPE, "Invalid ctype entry %d"},
+      {CPXERR_BAD_FILETYPE, "Invalid filetype"},
+      {CPXERR_BAD_LUB, "Invalid bound change indicator entry %d"},
+      {CPXERR_BAD_PARAM_NUM, "Invalid parameter number"},
+      {CPXERR_BAD_SENSE, "Invalid sense entry %d"},
+      {CPXERR_BAD_STATUS, "Invalid status entry %d for basis specificat"
+         "ion"},
+      {CPXERR_COL_INDEX_RANGE, "Column index %d out of range"},
+      {CPXERR_COUNT_RANGE, "Count entry %d negative or larger than allo"
+         "wed"},
+      {CPXERR_DUP_ENTRY, "Duplicate entry"},
+      {CPXERR_FAIL_OPEN_WRITE, "Could not open file '%s' for writing"},
+      {CPXERR_INDEX_RANGE, "Index is outside range of valid values"},
+      {CPXERR_NEGATIVE_SURPLUS, "Insufficient array length"},
+      {CPXERR_NO_BASIC_SOLN, "No basic solution exists"},
+      {CPXERR_NO_ENVIRONMENT, "No environment exists"},
+      {CPXERR_NO_FILENAME, "File name not specified"},
+      {CPXERR_NO_MEMORY, "Out of memory"},
+      {CPXERR_NO_PROBLEM, "No problem exists"},
+      {CPXERR_NO_SOLN, "No solution exists"},
+      {CPXERR_NOT_FIXED, "Only fixed variables are pivoted out"},
+      {CPXERR_NULL_NAME, "Null pointer %d in name array"},
+      {CPXERR_NULL_POINTER, "Null pointer for required data"},
+      {CPXERR_PARAM_TOO_BIG, "Parameter value too big"},
+      {CPXERR_PARAM_TOO_SMALL, "Parameter value too small"},
+      {CPXERR_ROW_INDEX_RANGE, "Row index %d out of range"},
+};
+
+/**********************************************************************/
+
+#define xassert glp_assert
+#define xprintf glp_printf
+#define xmalloc glp_malloc
+#define xcalloc glp_calloc
+#define xfree   glp_free
+
+/**********************************************************************/
+
+static int findintparam(int whichparam)
+{     int k, card;
+      card = sizeof(intparam) / sizeof(struct intparam);
+      for (k = 0; k < card; k++)
+         if (intparam[k].which == whichparam) return k;
+      return -1;
+}
+
+static int getintparam(CPXENV *env, int whichparam)
+{     int k;
+      xassert(env != NULL);
+      k = findintparam(whichparam);
+      xassert(k >= 0);
+      return env->intparam[k];
+}
+
+static int finddblparam(int whichparam)
+{     int k, card;
+      card = sizeof(dblparam) / sizeof(struct dblparam);
+      for (k = 0; k < card; k++)
+         if (dblparam[k].which == whichparam) return k;
+      return -1;
+}
+
+static double getdblparam(CPXENV *env, int whichparam)
+{     int k;
+      xassert(env != NULL);
+      k = finddblparam(whichparam);
+      xassert(k >= 0);
+      return env->dblparam[k];
+}
+
+static const char *finderrstring(int errcode)
+{     int k, card;
+      card = sizeof(errstring) / sizeof(struct errstring);
+      for (k = 0; k < card; k++)
+      {  if (errstring[k].code == errcode)
+            return errstring[k].string;
+      }
+      return NULL;
+}
+
+static int error(CPXENV *env, int errcode, ...)
+{     va_list arg;
+      char buffer[510];
+      xassert(env != NULL);
+      if (getintparam(env, CPX_PARAM_SCRIND) == CPX_ON)
+      {  xassert(CPXgeterrorstring(env, errcode, buffer) == buffer);
+         va_start(arg, errcode);
+         vprintf(buffer, arg);
+         va_end(arg);
+      }
+      return errcode;
+}
+
+static int checkenv(CPXENV *env)
+{     int errcode;
+      if (env == NULL)
+         errcode = CPXERR_NO_ENVIRONMENT;
+      else
+         errcode = 0;
+      return errcode;
+}
+
+static checklp(CPXENV *env, CPXLP *lp)
+{     int errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      if (lp == NULL)
+         errcode = error(env, CPXERR_NO_PROBLEM);
+done: return errcode;
+}
+
+static void invalidate(CPXLP *lp)
+{     lp->stat = 0;
+      lp->meth = CPX_ALG_NONE;
+      return;
+}
+
+static void enlargerflag(CPXLP *lp)
+{     int m;
+      xassert(lp != NULL);
+      m = glp_get_num_rows(lp->prob);
+      if (lp->rflen < m)
+      {  int rflen = lp->rflen;
+         char *rflag = lp->rflag;
+         while (lp->rflen < m)
+         {  lp->rflen += lp->rflen;
+            xassert(lp->rflen > 0);
+         }
+         lp->rflag = xcalloc(lp->rflen, sizeof(char));
+         memcpy(lp->rflag, rflag, rflen);
+         xfree(rflag);
+      }
+      return;
+}
+
+static void enlargeiwork(CPXLP *lp, int len)
+{     xassert(len >= 0);
+      if (lp->iwlen < len)
+      {  xfree(lp->iwork);
+         while (lp->iwlen < len)
+         {  lp->iwlen += lp->iwlen;
+            xassert(lp->iwlen > 0);
+         }
+         lp->iwork = xcalloc(lp->iwlen, sizeof(int));
+         memset(lp->iwork, 0, lp->iwlen * sizeof(int));
+      }
+      return;
+}
+
+/**********************************************************************/
+
+int CPXaddcols(CPXENV *env, CPXLP *lp, int ccnt, int nzcnt,
+      const double obj[], const int cmatbeg[], const int cmatind[],
+      const double cmatval[], const double lb[], const double ub[],
+      char *colname[])
+{     int j, k, m, n, beg, end, type, errcode;
+      double lbnd, ubnd;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (ccnt < 0 || nzcnt < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (ccnt > 0)
+      {  if (cmatbeg == NULL || cmatind == NULL || cmatval == NULL)
+         {  errcode = error(env, CPXERR_NULL_POINTER);
+            goto done;
+         }
+      }
+      m = glp_get_num_rows(lp->prob);
+      n = glp_get_num_cols(lp->prob);
+      enlargeiwork(lp, m);
+      for (j = 0; j < ccnt; j++)
+      {  beg = cmatbeg[j];
+         if (j > 0 && !(cmatbeg[j-1] <= beg))
+         {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
+            goto done;
+         }
+         if (!(0 <= beg && beg <= nzcnt))
+         {  errcode = error(env, CPXERR_INDEX_RANGE);
+            goto done;
+         }
+         end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
+         for (k = beg; k < end; k++)
+         {  if (!(0 <= cmatind[k] && cmatind[k] < m))
+            {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
+               goto done;
+            }
+         }
+         errcode = 0;
+         for (k = beg; k < end; k++)
+         {  if (lp->iwork[cmatind[k]])
+            {  errcode = error(env, CPXERR_DUP_ENTRY);
+               break;
+            }
+            lp->iwork[cmatind[k]] = 1;
+         }
+         for (k = beg; k < end; k++)
+            lp->iwork[cmatind[k]] = 0;
+         if (errcode) goto done;
+         if (colname != NULL)
+         {  if (colname[j] == NULL)
+            {  errcode = error(env, CPXERR_NULL_NAME, j);
+               goto done;
+            }
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      if (ccnt > 0)
+         glp_add_cols(lp->prob, ccnt);
+      for (j = 0; j < ccnt; j++)
+      {  if (colname != NULL)
+            glp_set_col_name(lp->prob, n+j+1, colname[j]);
+         lbnd = (lb == NULL ? 0.0 : lb[j]);
+         ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
+         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
+            type = GLP_FR;
+         else if (ubnd >= +CPX_INFBOUND)
+            type = GLP_LO;
+         else if (lbnd <= -CPX_INFBOUND)
+            type = GLP_UP;
+         else if (lbnd != ubnd)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
+         if (obj != NULL)
+            glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
+         beg = cmatbeg[j];
+         end = (j < ccnt-1 ? cmatbeg[j+1] : nzcnt);
+         for (k = beg; k < end; k++)
+            lp->iwork[k-beg] = cmatind[k]+1;
+         glp_set_mat_col(lp->prob, n+j+1, end-beg, lp->iwork-1,
+            cmatval+beg-1);
+         for (k = beg; k < end; k++)
+            lp->iwork[k-beg] = 0;
+      }
+done: return errcode;
+}
+
+int CPXaddrows(CPXENV *env, CPXLP *lp, int ccnt, int rcnt, int nzcnt,
+      const double rhs[], const char sense[], const int rmatbeg[],
+      const int rmatind[], const double rmatval[], char *colname[],
+      char *rowname[])
+{     int i, j, k, m, n, beg, end, type, errcode;
+      double temp;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (ccnt < 0 || rcnt < 0 || nzcnt < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (rcnt > 0)
+      {  if (rmatbeg == NULL || rmatind == NULL || rmatval == NULL)
+         {  errcode = error(env, CPXERR_NULL_POINTER);
+            goto done;
+         }
+      }
+      m = glp_get_num_rows(lp->prob);
+      n = glp_get_num_cols(lp->prob);
+      enlargeiwork(lp, n+ccnt);
+      for (i = 0; i < rcnt; i++)
+      {  if (sense != NULL)
+         {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
+                  sense[i] == 'G' || sense[i] == 'R'))
+            {  errcode = error(env, CPXERR_BAD_SENSE, i);
+               goto done;
+            }
+         }
+         beg = rmatbeg[i];
+         if (i > 0 && !(rmatbeg[i-1] <= beg))
+         {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, i);
+            goto done;
+         }
+         if (!(0 <= beg && beg <= nzcnt))
+         {  errcode = error(env, CPXERR_INDEX_RANGE);
+            goto done;
+         }
+         end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
+         for (k = beg; k < end; k++)
+         {  if (!(0 <= rmatind[k] && rmatind[k] < n+ccnt))
+            {  errcode = error(env, CPXERR_COL_INDEX_RANGE, k);
+               goto done;
+            }
+         }
+         errcode = 0;
+         for (k = beg; k < end; k++)
+         {  if (lp->iwork[rmatind[k]])
+            {  errcode = error(env, CPXERR_DUP_ENTRY);
+               break;
+            }
+            lp->iwork[rmatind[k]] = 1;
+         }
+         for (k = beg; k < end; k++)
+            lp->iwork[rmatind[k]] = 0;
+         if (errcode) goto done;
+         if (rowname != NULL)
+         {  if (rowname[i] == NULL)
+            {  errcode = error(env, CPXERR_NULL_NAME, i);
+               goto done;
+            }
+         }
+      }
+      for (j = 0; j < ccnt; j++)
+      {  if (colname != NULL)
+         {  if (colname[j] == NULL)
+            {  errcode = error(env, CPXERR_NULL_NAME, j);
+               goto done;
+            }
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      if (rcnt > 0)
+         glp_add_rows(lp->prob, rcnt);
+      if (ccnt > 0)
+         glp_add_cols(lp->prob, ccnt);
+      enlargerflag(lp);
+      for (i = 0; i < rcnt; i++)
+      {  if (rowname != NULL)
+            glp_set_row_name(lp->prob, m+i+1, rowname[i]);
+         temp = (rhs == NULL ? 0.0 : rhs[i]);
+         if (sense == NULL || sense[i] == 'E')
+         {  lp->rflag[m+i] = RF_NOT_RANGED;
+            type = GLP_FX;
+         }
+         else if (sense[i] == 'L')
+         {  lp->rflag[m+i] = RF_NOT_RANGED;
+            type = GLP_UP;
+         }
+         else if (sense[i] == 'G')
+         {  lp->rflag[m+i] = RF_NOT_RANGED;
+            type = GLP_LO;
+         }
+         else if (sense[i] == 'R')
+         {  lp->rflag[m+i] = RF_RANGED_POS;
+            type = GLP_FX;
+         }
+         else
+            xassert(sense != sense);
+         glp_set_row_bnds(lp->prob, m+i+1, type, temp, temp);
+         beg = rmatbeg[i];
+         end = (i < rcnt-1 ? rmatbeg[i+1] : nzcnt);
+         for (k = beg; k < end; k++)
+            lp->iwork[k-beg] = rmatind[k]+1;
+         glp_set_mat_row(lp->prob, m+i+1, end-beg, lp->iwork-1,
+            rmatval+beg-1);
+         for (k = beg; k < end; k++)
+            lp->iwork[k-beg] = 0;
+      }
+      for (j = 0; j < ccnt; j++)
+      {  if (colname != NULL)
+            glp_set_col_name(lp->prob, n+j+1, colname[j]);
+         glp_set_col_bnds(lp->prob, n+j+1, GLP_LO, 0.0, 0.0);
+      }
+done: return errcode;
+}
+
+int CPXbaropt(CPXENV *env, CPXLP *lp)
+{     xassert(env == env);
+      xassert(lp == lp);
+      xprintf("CPXbaropt: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXbinvrow(CPXENV *env, CPXLP *lp, int i, double y[])
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(i == i);
+      xassert(y == y);
+      xprintf("CPXbinvrow: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXchgbds(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
+      const char lu[], const double bd[])
+{     int j, n, type, errcode;
+      double lbnd, ubnd;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (cnt < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (cnt > 0)
+      {  if (indices == NULL || lu == NULL || bd == NULL)
+         {  errcode = error(env, CPXERR_NULL_POINTER);
+            goto done;
+         }
+      }
+      n = glp_get_num_cols(lp->prob);
+      for (j = 0; j < cnt; j++)
+      {  if (!(0 <= indices[j] && indices[j] < n))
+         {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
+            goto done;
+         }
+         if (!(lu[j] == 'L' || lu[j] == 'U' || lu[j] == 'B'))
+         {  errcode = error(env, CPXERR_BAD_LUB, j);
+            goto done;
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      for (j = 0; j < cnt; j++)
+      {  type = glp_get_col_type(lp->prob, indices[j]+1);
+         lbnd = glp_get_col_lb(lp->prob, indices[j]+1);
+         ubnd = glp_get_col_ub(lp->prob, indices[j]+1);
+         if (type == GLP_FR || type == GLP_UP)
+            lbnd = -CPX_INFBOUND;
+         if (type == GLP_FR || type == GLP_LO)
+            ubnd = +CPX_INFBOUND;
+         if (lu[j] == 'L')
+            lbnd = bd[j];
+         else if (lu[j] == 'U')
+            ubnd = bd[j];
+         else if (lu[j] == 'B')
+            lbnd = ubnd = bd[j];
+         else
+            xassert(lu != lu);
+         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
+            type = GLP_FR;
+         else if (ubnd >= +CPX_INFBOUND)
+            type = GLP_LO;
+         else if (lbnd <= -CPX_INFBOUND)
+            type = GLP_UP;
+         else if (lbnd != ubnd)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(lp->prob, indices[j]+1, type, lbnd, ubnd);
+      }
+done: return errcode;
+}
+
+int CPXchgcoeflist(CPXENV *env, CPXLP *lp, int numcoefs,
+      const int rowlist[], const int collist[], const double vallist[])
+{     int i, j, k, m, n, rcnt, ccnt, len, ptr, errcode;
+      int *head, *next, *ind;
+      double *val;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (numcoefs < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (numcoefs == 0)
+      {  errcode = 0;
+         goto done;
+      }
+      if (rowlist == NULL || collist == NULL || vallist == NULL)
+      {  errcode = error(env, CPXERR_NULL_POINTER);
+         goto done;
+      }
+      /* check triplets and determine the number of rows and columns
+         to be changed */
+      m = glp_get_num_rows(lp->prob);
+      n = glp_get_num_cols(lp->prob);
+      enlargeiwork(lp, m);
+      enlargeiwork(lp, n);
+      rcnt = ccnt = 0;
+      for (k = 0; k < numcoefs; k++)
+      {  i = rowlist[k];
+         if (!(0 <= i && i < m))
+         {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
+            goto done;
+         }
+         if (!(lp->iwork[i] & 0x01))
+            rcnt++, lp->iwork[i] |= 0x01;
+         j = collist[k];
+         if (!(0 <= j && j < n))
+         {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
+            goto done;
+         }
+         if (!(lp->iwork[j] & 0x02))
+            ccnt++, lp->iwork[j] |= 0x02;
+      }
+      memset(lp->iwork, 0, m * sizeof(int));
+      memset(lp->iwork, 0, n * sizeof(int));
+      errcode = 0;
+      invalidate(lp);
+      if (rcnt <= ccnt)
+      {  /* change the matrix by rows */
+         /* build the linked list of triplets:
+            head[i] is a pointer to first triplet for row i
+            next[k] is a pointer to next triplet for the same row */
+         head = xcalloc(m, sizeof(int));
+         for (i = 0; i < m; i++)
+            head[i] = -1;
+         next = xcalloc(numcoefs, sizeof(int));
+         for (k = 0; k < numcoefs; k++)
+         {  i = rowlist[k];
+            next[k] = head[i];
+            head[i] = k;
+         }
+         /* check duplicate columns */
+         for (i = 0; i < m; i++)
+         {  for (k = head[i]; k >= 0; k = next[k])
+            {  j = collist[k];
+               if (lp->iwork[j])
+               {  xfree(head);
+                  xfree(next);
+                  errcode = error(env, CPXERR_DUP_ENTRY);
+                  goto done;
+               }
+               lp->iwork[j] = 1;
+            }
+            for (k = head[i]; k >= 0; k = next[k])
+               lp->iwork[collist[k]] = 0;
+         }
+         /* perform operation */
+         ind = xcalloc(1+n, sizeof(int));
+         val = xcalloc(1+n, sizeof(double));
+         for (i = 0; i < m; i++)
+         {  if (head[i] < 0) continue;
+            len = glp_get_mat_row(lp->prob, i+1, ind, val);
+            for (ptr = 1; ptr <= len; ptr++)
+            {  j = ind[ptr]-1;
+               xassert(lp->iwork[j] == 0);
+               lp->iwork[j] = ptr;
+            }
+            for (k = head[i]; k >= 0; k = next[k])
+            {  j = collist[k];
+               if (lp->iwork[j] == 0)
+                  lp->iwork[j] = ++len;
+               ptr = lp->iwork[j];
+               ind[ptr] = j+1, val[ptr] = vallist[k];
+            }
+            glp_set_mat_row(lp->prob, i+1, len, ind, val);
+            for (ptr = 1; ptr <= len; ptr++)
+               lp->iwork[ind[ptr]-1] = 0;
+         }
+      }
+      else
+      {  /* change the matrix by columns */
+         /* build the linked lists of triplets:
+            head[j] is a pointer to first triplet for column j
+            next[k] is a pointer to next triplet for the same column */
+         head = xcalloc(n, sizeof(int));
+         for (j = 0; j < n; j++)
+            head[j] = -1;
+         next = xcalloc(numcoefs, sizeof(int));
+         for (k = 0; k < numcoefs; k++)
+         {  j = collist[k];
+            next[k] = head[j];
+            head[j] = k;
+         }
+         /* check duplicate rows */
+         for (j = 0; j < n; j++)
+         {  for (k = head[j]; k >= 0; k = next[k])
+            {  i = rowlist[k];
+               if (lp->iwork[i])
+               {  xfree(head);
+                  xfree(next);
+                  errcode = error(env, CPXERR_DUP_ENTRY);
+                  goto done;
+               }
+               lp->iwork[i] = 1;
+            }
+            for (k = head[j]; k >= 0; k = next[k])
+               lp->iwork[rowlist[k]] = 0;
+         }
+         /* perform operation */
+         ind = xcalloc(1+m, sizeof(int));
+         val = xcalloc(1+m, sizeof(double));
+         for (j = 0; j < n; j++)
+         {  if (head[j] < 0) continue;
+            len = glp_get_mat_col(lp->prob, j+1, ind, val);
+            for (ptr = 1; ptr <= len; ptr++)
+            {  i = ind[ptr]-1;
+               xassert(lp->iwork[i] == 0);
+               lp->iwork[i] = ptr;
+            }
+            for (k = head[j]; k >= 0; k = next[k])
+            {  i = rowlist[k];
+               if (lp->iwork[i] == 0)
+                  lp->iwork[i] = ++len;
+               ptr = lp->iwork[i];
+               ind[ptr] = i+1, val[ptr] = vallist[k];
+            }
+            glp_set_mat_col(lp->prob, j+1, len, ind, val);
+            for (ptr = 1; ptr <= len; ptr++)
+               lp->iwork[ind[ptr]-1] = 0;
+         }
+      }
+      xfree(head);
+      xfree(next);
+      xfree(ind);
+      xfree(val);
+done: return errcode;
+}
+
+void CPXchgobjsen(CPXENV *env, CPXLP *lp, int maxormin)
+{     int errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (!(maxormin == CPX_MIN || maxormin == CPX_MAX))
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      errcode = 0;
+      invalidate(lp);
+      if (maxormin == CPX_MIN)
+         glp_set_obj_dir(lp->prob, GLP_MIN);
+      else
+         glp_set_obj_dir(lp->prob, GLP_MAX);
+done: xassert(errcode == errcode);
+      return;
+}
+
+int CPXchgsense(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
+      const char sense[])
+{     int i, m, type, errcode;
+      double rhs;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (cnt < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (cnt > 0 && (indices == NULL || sense == NULL))
+      {  errcode = error(env, CPXERR_NULL_POINTER);
+         goto done;
+      }
+      m = glp_get_num_rows(lp->prob);
+      for (i = 0; i < cnt; i++)
+      {  if (!(0 <= indices[i] && indices[i] < m))
+         {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
+            goto done;
+         }
+         if (!(sense[i] == 'L' || sense[i] == 'E' || sense[i] == 'G' ||
+               sense[i] == 'R'))
+         {  errcode = error(env, CPXERR_BAD_SENSE, i);
+            goto done;
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      for (i = 0; i < cnt; i++)
+      {  type = glp_get_row_type(lp->prob, indices[i]+1);
+         if (lp->rflag[indices[i]] == RF_NOT_RANGED)
+         {  if (type == GLP_LO || type == GLP_FX)
+               rhs = glp_get_row_lb(lp->prob, indices[i]+1);
+            else if (type == GLP_UP)
+               rhs = glp_get_row_ub(lp->prob, indices[i]+1);
+            else
+               xassert(type != type);
+         }
+         else if (lp->rflag[indices[i]] == RF_RANGED_POS)
+         {  xassert(type == GLP_DB || type == GLP_FX);
+            rhs = glp_get_row_lb(lp->prob, indices[i]+1);
+         }
+         else if (lp->rflag[indices[i]] == RF_RANGED_NEG)
+         {  xassert(type == GLP_DB);
+            rhs = glp_get_row_ub(lp->prob, indices[i]+1);
+         }
+         else
+            xassert(lp != lp);
+         if (sense[i] == 'L')
+         {  lp->rflag[indices[i]] = RF_NOT_RANGED;
+            type = GLP_UP;
+         }
+         else if (sense[i] == 'E')
+         {  lp->rflag[indices[i]] = RF_NOT_RANGED;
+            type = GLP_FX;
+         }
+         else if (sense[i] == 'G')
+         {  lp->rflag[indices[i]] = RF_NOT_RANGED;
+            type = GLP_LO;
+         }
+         else if (sense[i] == 'R')
+         {  lp->rflag[indices[i]] = RF_RANGED_POS;
+            type = GLP_FX;
+         }
+         else
+            xassert(sense != sense);
+         glp_set_row_bnds(lp->prob, indices[i]+1, type, rhs, rhs);
+      }
+done: return errcode;
+}
+
+int CPXcloseCPLEX(CPXENV **_env)
+{     CPXENV *env;
+      CPXLP *lp;
+      int errcode;
+      if (_env == NULL)
+      {  errcode = CPXERR_NULL_POINTER;
+         goto done;
+      }
+      env = *_env;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      while (env->list != NULL)
+      {  lp = env->list;
+         errcode = CPXfreeprob(env, &lp);
+         xassert(!errcode);
+      }
+      xfree(env->intparam);
+      xfree(env->dblparam);
+      xfree(env);
+      *_env = NULL;
+      errcode = 0;
+done: return errcode;
+}
+
+int CPXcopybase(CPXENV *env, CPXLP *lp, const int cstat[],
+      const int rstat[])
+{     int i, j, m, n, stat, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      m = glp_get_num_rows(lp->prob);
+      n = glp_get_num_cols(lp->prob);
+      if (m > 0 && rstat == NULL || n > 0 && cstat == NULL)
+      {  errcode = error(env, CPXERR_NULL_POINTER);
+         goto done;
+      }
+      for (i = 0; i < m; i++)
+      {  if (!(rstat[i] == CPX_AT_LOWER || rstat[i] == CPX_BASIC ||
+               rstat[i] == CPX_AT_UPPER))
+         {  errcode = error(env, CPXERR_BAD_STATUS, i);
+            goto done;
+         }
+      }
+      for (j = 0; j < n; j++)
+      {  if (!(cstat[j] == CPX_AT_LOWER || cstat[j] == CPX_BASIC ||
+               cstat[j] == CPX_AT_UPPER || cstat[j] == CPX_FREE_SUPER))
+         {  errcode = error(env, CPXERR_BAD_STATUS, j);
+            goto done;
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      for (i = 0; i < m; i++)
+      {  if (rstat[i] == CPX_AT_LOWER)
+            stat = GLP_NL;
+         else if (rstat[i] == CPX_BASIC)
+            stat = GLP_BS;
+         else if (rstat[i] == CPX_AT_UPPER)
+            stat = GLP_NU;
+         else
+            xassert(rstat != rstat);
+         glp_set_row_stat(lp->prob, i+1, stat);
+      }
+      for (j = 0; j < n; j++)
+      {  if (cstat[j] == CPX_AT_LOWER)
+            stat = GLP_NL;
+         else if (cstat[j] == CPX_BASIC)
+            stat = GLP_BS;
+         else if (cstat[j] == CPX_AT_UPPER)
+            stat = GLP_NU;
+         else if (cstat[j] == CPX_FREE_SUPER)
+            stat = GLP_NF;
+         else
+            xassert(cstat != cstat);
+         glp_set_col_stat(lp->prob, j+1, stat);
+      }
+done: return errcode;
+}
+
+int CPXcopybasednorms(CPXENV *env, CPXLP *lp, const int cstat[],
+      const int rstat[], const double dnorm[])
+{     int errcode;
+      errcode = CPXcopybase(env, lp, cstat, rstat);
+      xassert(dnorm == dnorm);
+      return errcode;
+}
+
+int CPXcopylp(CPXENV *env, CPXLP *lp, int numcols, int numrows,
+      int objsen, const double obj[], const double rhs[],
+      const char sense[], const int matbeg[], const int matcnt[],
+      const int matind[], const double matval[], const double lb[],
+      const double ub[], const double rngval[])
+{     int errcode;
+      errcode = CPXcopylpwnames(env, lp, numcols, numrows, objsen, obj,
+         rhs, sense, matbeg, matcnt, matind, matval, lb, ub, rngval,
+         NULL, NULL);
+      return errcode;
+}
+
+int CPXcopylpwnames(CPXENV *env, CPXLP *lp, int numcols, int numrows,
+      int objsen, const double obj[], const double rhs[],
+      const char sense[], const int matbeg[], const int matcnt[],
+      const int matind[], const double matval[], const double lb[],
+      const double ub[], const double rngval[], char *colname[],
+      char *rowname[])
+{     int i, j, k, beg, end, type, errcode;
+      double lbnd, ubnd;
+      char name[255+1];
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (numcols < 0 || numrows < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (!(objsen == CPX_MIN || objsen == CPX_MAX))
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (numcols > 0)
+      {  if (matbeg == NULL || matcnt == NULL || matind == NULL ||
+               matval == NULL)
+         {  errcode = error(env, CPXERR_NULL_POINTER);
+            goto done;
+         }
+      }
+      for (i = 0; i < numrows; i++)
+      {  if (sense != NULL)
+         {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
+                  sense[i] == 'G' || sense[i] == 'R'))
+            {  errcode = error(env, CPXERR_BAD_SENSE, i);
+               goto done;
+            }
+         }
+         if (rowname != NULL)
+         {  if (rowname[i] == NULL)
+            {  errcode = error(env, CPXERR_NULL_NAME, i);
+               goto done;
+            }
+         }
+      }
+      enlargeiwork(lp, numrows);
+      for (j = 0; j < numcols; j++)
+      {  beg = matbeg[j];
+         if (j > 0 && !(matbeg[j-1] <= beg))
+         {  errcode = error(env, CPXERR_ARRAY_NOT_ASCENDING, j);
+            goto done;
+         }
+         if (beg < 0)
+         {  errcode = error(env, CPXERR_INDEX_RANGE);
+            goto done;
+         }
+         end = beg + matcnt[j];
+         if (!(beg <= end) || j < numcols-1 && !(end <= matbeg[j+1]))
+         {  errcode = error(env, CPXERR_COUNT_RANGE, j);
+            goto done;
+         }
+         for (k = beg; k < end; k++)
+         {  if (!(0 <= matind[k] && matind[k] < numrows))
+            {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, k);
+               goto done;
+            }
+         }
+         errcode = 0;
+         for (k = beg; k < end; k++)
+         {  if (lp->iwork[matind[k]])
+            {  errcode = error(env, CPXERR_DUP_ENTRY);
+               break;
+            }
+            lp->iwork[matind[k]] = 1;
+         }
+         for (k = beg; k < end; k++)
+            lp->iwork[matind[k]] = 0;
+         if (errcode) goto done;
+         if (colname != NULL)
+         {  if (colname[j] != NULL)
+            {  errcode = error(env, CPXERR_NULL_NAME, j);
+               goto done;
+            }
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      if (glp_get_prob_name(lp->prob) == NULL)
+         name[0] = '\0';
+      else
+         strcpy(name, glp_get_prob_name(lp->prob));
+      glp_erase_prob(lp->prob);
+      glp_set_prob_name(lp->prob, name);
+      if (objsen == CPX_MIN)
+         glp_set_obj_dir(lp->prob, GLP_MIN);
+      else if (objsen == CPX_MAX)
+         glp_set_obj_dir(lp->prob, GLP_MAX);
+      else
+         xassert(objsen != objsen);
+      if (numrows > 0)
+         glp_add_rows(lp->prob, numrows);
+      enlargerflag(lp);
+      for (i = 0; i < numrows; i++)
+      {  if (rowname != NULL)
+            glp_set_row_name(lp->prob, i+1, rowname[i]);
+         lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
+         if (sense == NULL || sense[i] == 'E')
+         {  lp->rflag[i] = RF_NOT_RANGED;
+            type = GLP_FX;
+         }
+         else if (sense[i] == 'L')
+         {  lp->rflag[i] = RF_NOT_RANGED;
+            type = GLP_UP;
+         }
+         else if (sense[i] == 'G')
+         {  lp->rflag[i] = RF_NOT_RANGED;
+            type = GLP_LO;
+         }
+         else if (sense[i] == 'R')
+         {  if (rngval == NULL || rngval[i] == 0.0)
+            {  lp->rflag[i] = RF_RANGED_POS;
+               type = GLP_FX;
+            }
+            else if (rngval[i] > 0.0)
+            {  lp->rflag[i] = RF_RANGED_POS;
+               type = GLP_DB;
+               ubnd += rngval[i];
+            }
+            else /* rngval[i] < 0.0 */
+            {  lp->rflag[i] = RF_RANGED_NEG;
+               type = GLP_DB;
+               lbnd += rngval[i];
+            }
+         }
+         else
+            xassert(sense != sense);
+         glp_set_row_bnds(lp->prob, i+1, type, lbnd, ubnd);
+      }
+      if (numcols > 0)
+         glp_add_cols(lp->prob, numcols);
+      for (j = 0; j < numcols; j++)
+      {  if (colname != NULL)
+            glp_set_col_name(lp->prob, j+1, colname[j]);
+         lbnd = (lb == NULL ? 0.0 : lb[j]);
+         ubnd = (ub == NULL ? +CPX_INFBOUND : ub[j]);
+         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
+            type = GLP_FR;
+         else if (ubnd >= +CPX_INFBOUND)
+            type = GLP_LO;
+         else if (lbnd <= -CPX_INFBOUND)
+            type = GLP_UP;
+         else if (lbnd != ubnd)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(lp->prob, j+1, type, lbnd, ubnd);
+         if (obj != NULL)
+            glp_set_obj_coef(lp->prob, j+1, obj[j]);
+         beg = matbeg[j];
+         end = beg + matcnt[j];
+         for (k = beg; k < end; k++)
+            lp->iwork[k-beg] = matind[k]+1;
+         glp_set_mat_col(lp->prob, j+1, end-beg, lp->iwork-1,
+            matval+beg-1);
+         for (k = beg; k < end; k++)
+            lp->iwork[k-beg] = 0;
+      }
+done: return errcode;
+}
+
+CPXLP *CPXcreateprob(CPXENV *env, int *status, const char *probname)
+{     CPXLP *lp = NULL;
+      int errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      lp = xmalloc(sizeof(struct CPXLP));
+      lp->env = env;
+      lp->prob = glp_create_prob();
+      glp_set_prob_name(lp->prob, probname);
+      lp->rflen = 100;
+      lp->rflag = xcalloc(lp->rflen, sizeof(char));
+      lp->iwlen = 100;
+      lp->iwork = xcalloc(lp->iwlen, sizeof(int));
+      memset(lp->iwork, 0, lp->iwlen * sizeof(int));
+      lp->link = env->list;
+      env->list = lp;
+      invalidate(lp);
+done: if (status != NULL) *status = errcode;
+      return lp;
+}
+
+int CPXdelcols(CPXENV *env, CPXLP *lp, int begin, int end)
+{     int j, n, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      n = glp_get_num_cols(lp->prob);
+      if (!(0 <= begin && begin <= end && end < n))
+      {  errcode = error(env, CPXERR_INDEX_RANGE);
+         goto done;
+      }
+      errcode = 0;
+      invalidate(lp);
+      enlargeiwork(lp, end-begin+1);
+      for (j = begin; j <= end; j++)
+         lp->iwork[j-begin] = j+1;
+      glp_del_cols(lp->prob, end-begin+1, lp->iwork-1);
+      for (j = begin; j <= end; j++)
+         lp->iwork[j-begin] = 0;
+done: return errcode;
+}
+
+int CPXdelrows(CPXENV *env, CPXLP *lp, int begin, int end)
+{     int i, m, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      m = glp_get_num_rows(lp->prob);
+      if (!(0 <= begin && begin <= end && end < m))
+      {  errcode = error(env, CPXERR_INDEX_RANGE);
+         goto done;
+      }
+      errcode = 0;
+      invalidate(lp);
+      enlargeiwork(lp, end-begin+1);
+      for (i = begin; i <= end; i++)
+         lp->iwork[i-begin] = i+1;
+      glp_del_rows(lp->prob, end-begin+1, lp->iwork-1);
+      for (i = begin; i <= end; i++)
+         lp->iwork[i-begin] = 0;
+      for (i = end+1; i < m; i++)
+         lp->rflag[i-(end-begin+1)] = lp->rflag[i];
+done: return errcode;
+}
+
+int CPXdelsetcols(CPXENV *env, CPXLP *lp, int delstat[])
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(delstat == delstat);
+      xprintf("CPXdelsetcols: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXdelsetrows(CPXENV *env, CPXLP *lp, int delstat[])
+{     int i, m, cnt, ind, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      m = glp_get_num_rows(lp->prob);
+      if (m > 0 && delstat == NULL)
+      {  errcode = error(env, CPXERR_NULL_POINTER);
+         goto done;
+      }
+      errcode = 0;
+      invalidate(lp);
+      enlargeiwork(lp, m);
+      cnt = ind = 0;
+      for (i = 0; i < m; i++)
+      {  if (delstat[i] == 1)
+         {  delstat[i] = -1;
+            lp->iwork[cnt++] = i+1;
+         }
+         else
+         {  delstat[i] = ind;
+            lp->rflag[ind++] = lp->rflag[i];
+         }
+      }
+      if (cnt > 0)
+         glp_del_rows(lp->prob, cnt, lp->iwork-1);
+      for (i = 0; i < cnt; i++)
+         lp->iwork[i] = 0;
+done: return errcode;
+}
+
+int CPXdualopt(CPXENV *env, CPXLP *lp);
+
+int CPXfreeprob(CPXENV *env, CPXLP **_lp)
+{     CPXLP *lp;
+      int errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      if (_lp == NULL)
+      {  errcode = error(env, CPXERR_NULL_POINTER);
+         goto done;
+      }
+      lp = *_lp;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      errcode = 0;
+      env = lp->env;
+      if (env->list == lp)
+         env->list = lp->link;
+      else
+      {  CPXLP *pp;
+         for (pp = env->list; pp != NULL; pp = pp->link)
+            if (pp->link == lp) break;
+         xassert(pp != NULL);
+         pp->link = lp->link;
+      }
+      glp_delete_prob(lp->prob);
+      xfree(lp->rflag);
+      xfree(lp->iwork);
+      xfree(lp);
+      *_lp = NULL;
+done: return errcode;
+}
+
+int CPXgetbase(CPXENV *env, CPXLP *lp, int cstat[], int rstat[])
+{     int i, j, m, n, stat, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (!lp->stat)
+      {  errcode = error(env, CPXERR_NO_SOLN);
+         goto done;
+      }
+      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+         ;
+      else
+      {  errcode = error(env, CPXERR_NO_BASIC_SOLN);
+         goto done;
+      }
+      errcode = 0;
+      if (rstat != NULL)
+      {  m = glp_get_num_rows(lp->prob);
+         for (i = 0; i < m; i++)
+         {  stat = glp_get_row_stat(lp->prob, i+1);
+            if (stat == GLP_BS)
+               rstat[i] = CPX_BASIC;
+            else if (lp->rflag[i] == RF_NOT_RANGED || stat != GLP_NU)
+               rstat[i] = CPX_AT_LOWER;
+            else
+               rstat[i] = CPX_AT_UPPER;
+         }
+      }
+      if (cstat != NULL)
+      {  n = glp_get_num_cols(lp->prob);
+         for (j = 0; j < n; j++)
+         {  stat = glp_get_col_stat(lp->prob, j+1);
+            if (stat == GLP_BS)
+               cstat[j] = CPX_BASIC;
+            else if (stat == GLP_NU)
+               cstat[j] = CPX_AT_UPPER;
+            else if (stat == GLP_NF)
+               cstat[j] = CPX_FREE_SUPER;
+            else
+               cstat[j] = CPX_AT_LOWER;
+         }
+      }
+done: return errcode;
+}
+
+int CPXgetbasednorms(CPXENV *env, CPXLP *lp, int cstat[], int rstat[],
+      double dnorm[])
+{     int i, m, errcode;
+      errcode = CPXgetbase(env, lp, cstat, rstat);
+      if (errcode) goto done;
+      if (dnorm != NULL)
+      {  m = glp_get_num_rows(lp->prob);
+         for (i = 0; i < m; i++) dnorm[i] = 1.0;
+      }
+done: return errcode;
+}
+
+int CPXgetbhead(CPXENV *env, CPXLP *lp, int head[], double x[])
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(head == head);
+      xassert(x == x);
+      xprintf("CPXgetbhead: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXgetdblparam(CPXENV *env, int whichparam, double *value)
+{     int k, errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      k = finddblparam(whichparam);
+      if (k < 0)
+      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
+         goto done;
+      }
+      errcode = 0;
+      if (value != NULL)
+         *value = env->dblparam[k];
+done: return errcode;
+}
+
+int CPXgetdj(CPXENV *env, CPXLP *lp, double dj[], int begin, int end)
+{     int j, n, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      n = glp_get_num_cols(lp->prob);
+      if (!(0 <= begin && begin <= end && end < n))
+      {  errcode = error(env, CPXERR_INDEX_RANGE);
+         goto done;
+      }
+      if (!lp->stat)
+      {  errcode = error(env, CPXERR_NO_SOLN);
+         goto done;
+      }
+      errcode = 0;
+      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+      {  if (dj != NULL)
+         {  for (j = begin; j <= end; j++)
+               dj[j-begin] = glp_get_col_dual(lp->prob, j+1);
+         }
+      }
+      else
+         xassert(lp != lp);
+done: return errcode;
+}
+
+char *CPXgeterrorstring(CPXENV *env, int errcode, char *buffer)
+{     const char *string;
+      xassert(env == env);
+      string = finderrstring(errcode);
+      if (string == NULL)
+         buffer = NULL;
+      else
+         sprintf(buffer, "CPLEX Error %5d:  %s.\n", errcode, string);
+      return buffer;
+}
+
+int CPXgetijdiv(CPXENV *env, CPXLP *lp, int *idiv, int *jdiv)
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(idiv == idiv);
+      xassert(jdiv == jdiv);
+      xprintf("CPXgetijdiv: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXgetintparam(CPXENV *env, int whichparam, int *value)
+{     int k, errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      k = findintparam(whichparam);
+      if (k < 0)
+      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
+         goto done;
+      }
+      errcode = 0;
+      if (value != NULL)
+         *value = env->intparam[k];
+done: return errcode;
+}
+
+int CPXgetlb(CPXENV *env, CPXLP *lp, double lb[], int begin, int end)
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(lb == lb);
+      xassert(begin == begin);
+      xassert(end == end);
+      xprintf("CPXgetlb: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXgetmethod(CPXENV *env, CPXLP *lp)
+{     int method;
+      if (checklp(env, lp))
+         method = CPX_ALG_NONE;
+      else
+         method = lp->meth;
+      return method;
+}
+
+int CPXgetnumcols(CPXENV *env, CPXLP *lp)
+{     int numcols;
+      if (checklp(env, lp))
+         numcols = 0;
+      else
+         numcols = glp_get_num_cols(lp->prob);
+      return numcols;
+}
+
+int CPXgetnumnz(CPXENV *env, CPXLP *lp)
+{     int numnz;
+      if (checklp(env, lp))
+         numnz = 0;
+      else
+         numnz = glp_get_num_nz(lp->prob);
+      return numnz;
+}
+
+int CPXgetnumrows(CPXENV *env, CPXLP *lp)
+{     int numrows;
+      if (checklp(env, lp))
+         numrows = 0;
+      else
+         numrows = glp_get_num_rows(lp->prob);
+      return numrows;
+}
+
+int CPXgetobjval(CPXENV *env, CPXLP *lp, double *objval)
+{     int errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (!lp->stat)
+      {  errcode = error(env, CPXERR_NO_SOLN);
+         goto done;
+      }
+      errcode = 0;
+      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+      {  if (objval != NULL)
+            *objval = glp_get_obj_val(lp->prob);
+      }
+      else
+         xassert(lp != lp);
+done: return errcode;
+}
+
+int CPXgetpi(CPXENV *env, CPXLP *lp, double pi[], int begin, int end)
+{     int i, m, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      m = glp_get_num_rows(lp->prob);
+      if (!(0 <= begin && begin <= end && end < m))
+      {  errcode = error(env, CPXERR_INDEX_RANGE);
+         goto done;
+      }
+      if (!lp->stat)
+      {  errcode = error(env, CPXERR_NO_SOLN);
+         goto done;
+      }
+      errcode = 0;
+      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+      {  if (pi != NULL)
+         {  for (i = begin; i <= end; i++)
+               pi[i-begin] = glp_get_row_dual(lp->prob, i+1);
+         }
+      }
+      else
+         xassert(lp != lp);
+done: return errcode;
+}
+
+int CPXgetsense(CPXENV *env, CPXLP *lp, char sense[], int begin,
+      int end)
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(sense == sense);
+      xassert(begin == begin);
+      xassert(end == end);
+      xprintf("CPXgetsense: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXgetslack(CPXENV *env, CPXLP *lp, double slack[], int begin,
+      int end)
+{     int i, m, type, errcode;
+      double temp;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      m = glp_get_num_rows(lp->prob);
+      if (!(0 <= begin && begin <= end && end < m))
+      {  errcode = error(env, CPXERR_INDEX_RANGE);
+         goto done;
+      }
+      if (!lp->stat)
+      {  errcode = error(env, CPXERR_NO_SOLN);
+         goto done;
+      }
+      errcode = 0;
+      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+      {  if (slack != NULL)
+         {  for (i = begin; i <= end; i++)
+            {  type = glp_get_row_type(lp->prob, i+1);
+               temp = glp_get_row_prim(lp->prob, i+1);
+               if (lp->rflag[i] == RF_NOT_RANGED)
+               {  if (type == GLP_LO || type == GLP_FX)
+                     slack[i-begin] =
+                        glp_get_row_lb(lp->prob, i+1) - temp;
+                  else if (type == GLP_UP)
+                     slack[i-begin] =
+                        glp_get_row_ub(lp->prob, i+1) - temp;
+                  else
+                     xassert(type != type);
+               }
+               else if (lp->rflag[i] == RF_RANGED_POS)
+               {  xassert(type == GLP_DB || type == GLP_FX);
+                  slack[i-begin] =
+                     temp - glp_get_row_lb(lp->prob, i+1);
+               }
+               else if (lp->rflag[i] == RF_RANGED_NEG)
+               {  xassert(type == GLP_DB);
+                  slack[i-begin] =
+                     temp - glp_get_row_ub(lp->prob, i+1);
+               }
+               else
+                  xassert(lp != lp);
+            }
+         }
+      }
+      else
+         xassert(lp != lp);
+done: return errcode;
+}
+
+int CPXgetstat(CPXENV *env, CPXLP *lp)
+{     int stat;
+      if (checklp(env, lp))
+         stat = 0;
+      else
+         stat = lp->stat;
+      return stat;
+}
+
+int CPXgetub(CPXENV *env, CPXLP *lp, double ub[], int begin, int end)
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(ub == ub);
+      xassert(begin == begin);
+      xassert(end == end);
+      xprintf("CPXgetub: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXgetweight(CPXENV *env, CPXLP *lp, int rcnt, const int rmatbeg[],
+      const int rmatind[], const double rmatval[], double weight[],
+      int dpriind)
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(rcnt == rcnt);
+      xassert(rmatbeg == rmatbeg);
+      xassert(rmatind == rmatind);
+      xassert(rmatval == rmatval);
+      xassert(weight == weight);
+      xassert(dpriind == dpriind);
+      xprintf("CPXgetweight: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXgetx(CPXENV *env, CPXLP *lp, double x[], int begin, int end)
+{     int j, n, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      n = glp_get_num_cols(lp->prob);
+      if (!(0 <= begin && begin <= end && end < n))
+      {  errcode = error(env, CPXERR_INDEX_RANGE);
+         goto done;
+      }
+      if (!lp->stat)
+      {  errcode = error(env, CPXERR_NO_SOLN);
+         goto done;
+      }
+      errcode = 0;
+      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+      {  if (x != NULL)
+         {  for (j = begin; j <= end; j++)
+               x[j-begin] = glp_get_col_prim(lp->prob, j+1);
+         }
+      }
+      else
+         xassert(lp != lp);
+done: return errcode;
+}
+
+int CPXinfodblparam(CPXENV *env, int whichparam, double *defvalue,
+      double *minvalue, double *maxvalue)
+{     int k, errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      k = finddblparam(whichparam);
+      if (k < 0)
+      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
+         goto done;
+      }
+      errcode = 0;
+      if (defvalue != NULL)
+         *defvalue = dblparam[k].defv;
+      if (minvalue != NULL)
+         *minvalue = dblparam[k].minv;
+      if (maxvalue != NULL)
+         *maxvalue = dblparam[k].maxv;
+done: return errcode;
+}
+
+int CPXinfointparam(CPXENV *env, int whichparam, int *defvalue,
+      int *minvalue, int *maxvalue)
+{     int k, errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      k = findintparam(whichparam);
+      if (k < 0)
+      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
+         goto done;
+      }
+      errcode = 0;
+      if (defvalue != NULL)
+         *defvalue = intparam[k].defv;
+      if (minvalue != NULL)
+         *minvalue = intparam[k].minv;
+      if (maxvalue != NULL)
+         *maxvalue = intparam[k].maxv;
+done: return errcode;
+}
+
+int CPXmdleave(const CPXENV *env, CPXLP *lp, const int goodlist[],
+      int goodlen, double downratio[], double upratio[])
+{     int k;
+      xassert(env == env);
+      xassert(lp == lp);
+      xassert(goodlist == goodlist);
+      xassert(goodlen >= 0);
+      xassert(downratio != NULL);
+      xassert(upratio != NULL);
+      /* not implemented yet */
+      for (k = 0; k < goodlen; k++)
+         downratio[k] = upratio[k] = 0.0;
+      return 0;
+}
+
+int CPXnewcols(CPXENV *env, CPXLP *lp, int ccnt, const double obj[],
+      const double lb[], const double ub[], const char ctype[],
+      char *colname[])
+{     int j, n, kind, type, errcode;
+      double lbnd, ubnd;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (ccnt < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      for (j = 0; j < ccnt; j++)
+      {  if (ctype != NULL)
+         {  if (!(ctype[j] == 'C' || ctype[j] == 'B' ||
+                  ctype[j] == 'I'))
+            {  errcode = error(env, CPXERR_BAD_CTYPE, j);
+               goto done;
+            }
+         }
+         if (colname != NULL)
+         {  if (colname[j] == NULL)
+            {  errcode = error(env, CPXERR_NULL_NAME, j);
+               goto done;
+            }
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      n = glp_get_num_cols(lp->prob);
+      if (ccnt > 0)
+         glp_add_cols(lp->prob, ccnt);
+      for (j = 0; j < ccnt; j++)
+      {  if (colname != NULL)
+            glp_set_col_name(lp->prob, n+j+1, colname[j]);
+         if (obj != NULL)
+            glp_set_obj_coef(lp->prob, n+j+1, obj[j]);
+         lbnd = (lb == NULL ? 0.0 : lb[j]);
+         ubnd = (ub == NULL ? 0.0 : ub[j]);
+         if (lbnd <= -CPX_INFBOUND && ubnd >= +CPX_INFBOUND)
+            type = GLP_FR;
+         else if (ubnd >= +CPX_INFBOUND)
+            type = GLP_LO;
+         else if (lbnd <= -CPX_INFBOUND)
+            type = GLP_UP;
+         else if (lbnd != ubnd)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(lp->prob, n+j+1, type, lbnd, ubnd);
+         if (ctype != NULL)
+         {  if (ctype[j] == 'C')
+               kind = GLP_CV;
+            else if (ctype[j] == 'B')
+               kind = GLP_BV;
+            else if (ctype[j] == 'I')
+               kind = GLP_IV;
+            else
+               xassert(ctype != ctype);
+            glp_set_col_kind(lp->prob, n+j+1, kind);
+         }
+      }
+done: return errcode;
+}
+
+int CPXnewrows(CPXENV *env, CPXLP *lp, int rcnt, const double rhs[],
+      const char sense[], const double rngval[], char *rowname[])
+{     int i, m, type, errcode;
+      double lbnd, ubnd;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (rcnt < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      for (i = 0; i < rcnt; i++)
+      {  if (sense != NULL)
+         {  if (!(sense[i] == 'L' || sense[i] == 'E' ||
+                  sense[i] == 'G' || sense[i] == 'R'))
+            {  errcode = error(env, CPXERR_BAD_SENSE, i);
+               goto done;
+            }
+         }
+         if (rowname != NULL)
+         {  if (rowname[i] == NULL)
+            {  errcode = error(env, CPXERR_NULL_NAME, i);
+               goto done;
+            }
+         }
+      }
+      errcode = 0;
+      invalidate(lp);
+      m = glp_get_num_rows(lp->prob);
+      if (rcnt > 0)
+         glp_add_rows(lp->prob, rcnt);
+      enlargerflag(lp);
+      for (i = 0; i < rcnt; i++)
+      {  if (rowname != NULL)
+            glp_set_row_name(lp->prob, m+i+1, rowname[i]);
+         lbnd = ubnd = (rhs == NULL ? 0.0 : rhs[i]);
+         if (sense == NULL || sense[i] == 'E')
+         {  lp->rflag[m+i] = RF_NOT_RANGED;
+            type = GLP_FX;
+         }
+         else if (sense[i] == 'L')
+         {  lp->rflag[m+i] = RF_NOT_RANGED;
+            type = GLP_UP;
+         }
+         else if (sense[i] == 'G')
+         {  lp->rflag[m+i] = RF_NOT_RANGED;
+            type = GLP_LO;
+         }
+         else if (sense[i] == 'R')
+         {  if (rngval == NULL || rngval[i] == 0.0)
+            {  lp->rflag[m+i] = RF_RANGED_POS;
+               type = GLP_FX;
+            }
+            else if (rngval[i] > 0.0)
+            {  lp->rflag[m+i] = RF_RANGED_POS;
+               type = GLP_DB;
+               ubnd += rngval[i];
+            }
+            else /* rngval[i] < 0.0 */
+            {  lp->rflag[m+i] = RF_RANGED_NEG;
+               type = GLP_DB;
+               lbnd += rngval[i];
+            }
+         }
+         else
+            xassert(sense != sense);
+         glp_set_row_bnds(lp->prob, m+i+1, type, lbnd, ubnd);
+      }
+done: return errcode;
+}
+
+CPXENV *CPXopenCPLEX(int *status)
+{     CPXENV *env;
+      int k, card;
+      env = xmalloc(sizeof(CPXENV));
+      env->list = NULL;
+      card = sizeof(intparam) / sizeof(struct intparam);
+      env->intparam = xcalloc(card, sizeof(int));
+      for (k = 0; k < card; k++)
+         env->intparam[k] = intparam[k].defv;
+      card = sizeof(dblparam) / sizeof(struct dblparam);
+      env->dblparam = xcalloc(card, sizeof(double));
+      for (k = 0; k < card; k++)
+         env->dblparam[k] = dblparam[k].defv;
+      if (status != NULL) *status = 0;
+      return env;
+}
+
+int CPXpivotin(CPXENV *env, CPXLP *lp, const int rlist[], int rlen)
+{     int i, m, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (rlen < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (rlen > 0 && rlist == NULL)
+      {  errcode = error(env, CPXERR_NULL_POINTER);
+         goto done;
+      }
+      m = glp_get_num_rows(lp->prob);
+      for (i = 0; i < rlen; i++)
+      {  if (!(0 <= rlist[i] && rlist[i] < m))
+         {  errcode = error(env, CPXERR_ROW_INDEX_RANGE, i);
+            goto done;
+         }
+      }
+      errcode = 0;
+      for (i = 0; i < rlen; i++)
+      {  if (glp_get_row_type(lp->prob, rlist[i]+1) != GLP_FX)
+         {  if (glp_get_row_stat(lp->prob, rlist[i]+1) != GLP_BS)
+            {  /* not implemented yet */
+               break;
+            }
+         }
+      }
+done: return errcode;
+}
+
+int CPXpivotout(CPXENV *env, CPXLP *lp, const int clist[], int clen)
+{     int j, n, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (clen < 0)
+      {  errcode = error(env, CPXERR_BAD_ARGUMENT);
+         goto done;
+      }
+      if (clen > 0 && clist == NULL)
+      {  errcode = error(env, CPXERR_NULL_POINTER);
+         goto done;
+      }
+      n = glp_get_num_cols(lp->prob);
+      for (j = 0; j < clen; j++)
+      {  if (!(0 <= clist[j] && clist[j] < n))
+         {  errcode = error(env, CPXERR_COL_INDEX_RANGE, j);
+            goto done;
+         }
+         if (glp_get_col_type(lp->prob, clist[j]+1) != GLP_FX)
+         {  errcode = error(env, CPXERR_NOT_FIXED);
+            goto done;
+         }
+      }
+      errcode = 0;
+      for (j = 0; j < clen; j++)
+      {  if (glp_get_col_stat(lp->prob, clist[j]+1) == GLP_BS)
+         {  /* not implemented yet */
+            break;
+         }
+      }
+done: return errcode;
+}
+
+int CPXprimopt(CPXENV *env, CPXLP *lp);
+
+int CPXsavwrite(CPXENV *env, CPXLP *lp, const char *filename)
+{     xassert(env == env);
+      xassert(lp == lp);
+      xassert(filename == filename);
+      xprintf("CPXsavwrite: not implemented yet\n");
+      exit(EXIT_FAILURE);
+      return -1;
+}
+
+int CPXsetdblparam(CPXENV *env, int whichparam, double newvalue)
+{     int k, errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      k = finddblparam(whichparam);
+      if (k < 0)
+      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
+         goto done;
+      }
+      if (newvalue < dblparam[k].minv)
+      {  errcode = error(env, CPXERR_PARAM_TOO_SMALL);
+         goto done;
+      }
+      if (newvalue > dblparam[k].maxv)
+      {  errcode = error(env, CPXERR_PARAM_TOO_BIG);
+         goto done;
+      }
+      errcode = 0;
+      env->dblparam[k] = newvalue;
+done: return errcode;
+}
+
+int CPXsetintparam(CPXENV *env, int whichparam, int newvalue)
+{     int k, errcode;
+      errcode = checkenv(env);
+      if (errcode) goto done;
+      k = findintparam(whichparam);
+      if (k < 0)
+      {  errcode = error(env, CPXERR_BAD_PARAM_NUM);
+         goto done;
+      }
+      if (newvalue < intparam[k].minv)
+      {  errcode = error(env, CPXERR_PARAM_TOO_SMALL);
+         goto done;
+      }
+      if (newvalue > intparam[k].maxv)
+      {  errcode = error(env, CPXERR_PARAM_TOO_BIG);
+         goto done;
+      }
+      errcode = 0;
+      env->intparam[k] = newvalue;
+done: return errcode;
+}
+
+int CPXsolninfo(CPXENV *env, CPXLP *lp, int *solnmethod, int *solntype,
+      int *pfeasind, int *dfeasind)
+{     int type, pfeas, dfeas, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      errcode = 0;
+      if (!lp->stat)
+         type = CPX_NO_SOLN, pfeas = dfeas = 0;
+      else if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+      {  type = CPX_BASIC_SOLN;
+         pfeas = (glp_get_prim_stat(lp->prob) == GLP_FEAS);
+         dfeas = (glp_get_dual_stat(lp->prob) == GLP_FEAS);
+      }
+      else
+         xassert(lp != lp);
+      if (solnmethod != NULL)
+         *solnmethod = lp->meth;
+      if (solntype != NULL)
+         *solntype = type;
+      if (pfeasind != NULL)
+         *pfeasind = pfeas;
+      if (dfeasind != NULL)
+         *dfeasind = dfeas;
+done: return errcode;
+}
+
+int CPXsolution(CPXENV *env, CPXLP *lp, int *lpstat, double *objval,
+      double x[], double pi[], double slack[], double dj[])
+{     int m, n, errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (!lp->stat)
+      {  errcode = error(env, CPXERR_NO_SOLN);
+         goto done;
+      }
+      errcode = 0;
+      m = glp_get_num_rows(lp->prob);
+      n = glp_get_num_cols(lp->prob);
+      if (lp->meth == CPX_ALG_PRIMAL || lp->meth == CPX_ALG_DUAL)
+      {  if (lpstat != NULL)
+            *lpstat = CPXgetstat(env, lp);
+         if (objval != NULL)
+            xassert(CPXgetobjval(env, lp, objval) == 0);
+         if (x != NULL)
+            xassert(CPXgetx(env, lp, x, 0, n-1) == 0);
+         if (pi != NULL)
+            xassert(CPXgetpi(env, lp, pi, 0, m-1) == 0);
+         if (slack != NULL)
+            xassert(CPXgetslack(env, lp, slack, 0, m-1) == 0);
+         if (dj != NULL)
+            xassert(CPXgetdj(env, lp, dj, 0, n-1) == 0);
+      }
+      else
+         xassert(lp != lp);
+done: return errcode;
+}
+
+int CPXstrongbranch(CPXENV *env, CPXLP *lp, const int goodlist[],
+      int goodlen, double downpen[], double uppen[], int itlim)
+{     int k;
+      xassert(env == env);
+      xassert(lp == lp);
+      xassert(goodlist == goodlist);
+      xassert(goodlen >= 0);
+      xassert(downpen != NULL);
+      xassert(uppen != NULL);
+      xassert(itlim == itlim);
+      /* not implemented yet */
+      for (k = 0; k < goodlen; k++)
+         downpen[k] = uppen[k] = 0.0;
+      return 0;
+}
+
+static int xstrcasecmp(const char *s1, const char *s2)
+{     int c1, c2;
+      for (;;)
+      {  c1 = toupper((unsigned char)*s1++);
+         c2 = toupper((unsigned char)*s2++);
+         if (c1 == '\0' || c1 != c2) break;
+      }
+      return c1 - c2;
+}
+
+static void getfiletype(const char *filename, char type[3+1])
+{     /* determine filetype from filename */
+      int beg, end;
+      beg = end = strlen(filename);
+      while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
+         beg--;
+      if (beg > 0 && filename[beg-1] == '.' &&
+          xstrcasecmp(&filename[beg], "gz") == 0)
+      {  end = --beg;
+         while (beg > 0 && filename[beg-1] != '.' && end - beg < 3)
+            beg--;
+      }
+      if (beg > 0 && filename[beg-1] == '.')
+      {  memcpy(type, &filename[beg], end - beg);
+         type[end - beg] = '\0';
+      }
+      else
+         type[0] = '\0';
+      return;
+}
+
+int CPXwriteprob(CPXENV *env, CPXLP *lp, const char *filename,
+      const char *filetype)
+{     glp_prob *copy;
+      int errcode;
+      char type[3+1];
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      if (filename == NULL)
+      {  errcode = error(env, CPXERR_NO_FILENAME);
+         goto done;
+      }
+      if (filetype == NULL)
+         getfiletype(filename, type), filetype = type;
+      if (xstrcasecmp(filetype, "MPS") == 0)
+      {  glp_term_out(GLP_OFF);
+         errcode = glp_write_mps(lp->prob, GLP_MPS_FILE, NULL, filename)
+            ;
+         glp_term_out(GLP_ON);
+      }
+      else if (xstrcasecmp(filetype, "LP") == 0)
+      {  glp_term_out(GLP_OFF);
+         errcode = glp_write_lp(lp->prob, NULL, filename);
+         glp_term_out(GLP_ON);
+      }
+      else if (xstrcasecmp(filetype, "RMP") == 0 ||
+               xstrcasecmp(filetype, "REW") == 0)
+      {  copy = glp_create_prob();
+         glp_copy_prob(copy, lp->prob, GLP_OFF);
+         glp_term_out(GLP_OFF);
+         errcode = glp_write_mps(copy, GLP_MPS_DECK, NULL, filename);
+         glp_term_out(GLP_ON);
+         glp_delete_prob(copy);
+      }
+      else if (xstrcasecmp(filetype, "RLP") == 0)
+      {  copy = glp_create_prob();
+         glp_copy_prob(copy, lp->prob, GLP_OFF);
+         glp_term_out(GLP_OFF);
+         errcode = glp_write_lp(copy, NULL, filename);
+         glp_term_out(GLP_ON);
+         glp_delete_prob(copy);
+      }
+      else
+      {  errcode = error(env, CPXERR_BAD_FILETYPE);
+         goto done;
+      }
+      if (errcode)
+         errcode = error(env, CPXERR_FAIL_OPEN_WRITE, filename);
+done: return errcode;
+}
+
+/**********************************************************************/
+
+static int solvelp(CPXENV *env, CPXLP *lp, int meth)
+{     glp_smcp parm;
+      int errcode;
+      errcode = checklp(env, lp);
+      if (errcode) goto done;
+      errcode = 0;
+      invalidate(lp);
+      glp_init_smcp(&parm);
+      switch (meth)
+      {  case CPX_ALG_PRIMAL:
+            parm.meth = GLP_PRIMAL;
+            break;
+         case CPX_ALG_DUAL:
+            parm.meth = GLP_DUAL;
+            break;
+         default:
+            xassert(meth != meth);
+      }
+      switch (getintparam(env, CPX_PARAM_SIMDISPLAY))
+      {  case 0:
+            parm.msg_lev = GLP_MSG_OFF;
+            break;
+         case 1:
+            parm.msg_lev = GLP_MSG_ALL;
+            break;
+         case 2:
+            parm.msg_lev = GLP_MSG_ALL;
+            parm.out_frq = 1;
+            break;
+         default:
+            xassert(env != env);
+      }
+      xassert(getdblparam == getdblparam);
+      switch (getintparam(env, CPX_PARAM_ADVIND))
+      {  case 0:
+            glp_term_out(GLP_OFF);
+            glp_adv_basis(lp->prob, 0);
+            glp_term_out(GLP_ON);
+            break;
+         case 1:
+         case 2:
+            break;
+         default:
+            xassert(env != env);
+      }
+      if (!glp_bf_exists(lp->prob))
+      {  if (glp_factorize(lp->prob) != 0)
+         {  glp_term_out(GLP_OFF);
+            glp_adv_basis(lp->prob, 0);
+            glp_term_out(GLP_ON);
+            if (glp_factorize(lp->prob) != 0)
+               glp_std_basis(lp->prob);
+         }
+      }
+      xassert(glp_simplex(lp->prob, &parm) == 0);
+      switch (glp_get_status(lp->prob))
+      {  case GLP_OPT:
+            lp->stat = CPX_STAT_OPTIMAL;
+            lp->meth = meth;
+            break;
+         case GLP_NOFEAS:
+            lp->stat = CPX_STAT_INFEASIBLE;
+            lp->meth = meth;
+            break;
+         case GLP_UNBND:
+            lp->stat = CPX_STAT_UNBOUNDED;
+            lp->meth = meth;
+            break;
+         default:
+            xassert(lp != lp);
+      }
+done: return errcode;
+}
+
+int CPXprimopt(CPXENV *env, CPXLP *lp)
+{     int errcode;
+      errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
+      return errcode;
+}
+
+int CPXdualopt(CPXENV *env, CPXLP *lp)
+{     int errcode;
+      errcode = solvelp(env, lp, CPX_ALG_DUAL);
+      return errcode;
+}
+
+int CPXlpopt(CPXENV *env, CPXLP *lp)
+{     int errcode;
+      errcode = solvelp(env, lp, CPX_ALG_PRIMAL);
+      return errcode;
+}
+
+/* eof */
Index: deps/glpk/examples/cplex/cplex.h
===================================================================
--- deps/glpk/examples/cplex/cplex.h	(revision 9)
+++ deps/glpk/examples/cplex/cplex.h	(revision 9)
@@ -0,0 +1,301 @@
+/* cplex.h (CPLEX-like interface to GLPK API) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef _CPLEX_H
+#define _CPLEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct CPXENV CPXENV, *CPXENVptr;
+typedef struct CPXLP CPXLP, *CPXLPptr;
+
+#define CPX_VERSION                 900
+
+#define CPX_OFF                     0
+#define CPX_ON                      1
+
+#define CPX_INFBOUND                1e20
+
+/* error codes: */
+#define CPXERR_NO_MEMORY            1001
+#define CPXERR_NO_ENVIRONMENT       1002
+#define CPXERR_BAD_ARGUMENT         1003
+#define CPXERR_NULL_POINTER         1004
+#define CPXERR_NO_PROBLEM           1009
+#define CPXERR_BAD_PARAM_NUM        1013
+#define CPXERR_PARAM_TOO_SMALL      1014
+#define CPXERR_PARAM_TOO_BIG        1015
+#define CPXERR_INDEX_RANGE          1200
+#define CPXERR_COL_INDEX_RANGE      1201
+#define CPXERR_ROW_INDEX_RANGE      1203
+#define CPXERR_NEGATIVE_SURPLUS     1207
+#define CPXERR_BAD_SENSE            1215
+#define CPXERR_NO_SOLN              1217
+#define CPXERR_NOT_FIXED            1221
+#define CPXERR_DUP_ENTRY            1222
+#define CPXERR_NULL_NAME            1224
+#define CPXERR_ARRAY_NOT_ASCENDING  1226
+#define CPXERR_COUNT_RANGE          1227
+#define CPXERR_BAD_LUB              1229
+#define CPXERR_BAD_STATUS           1253
+#define CPXERR_NO_BASIC_SOLN        1261
+#define CPXERR_NO_FILENAME          1421
+#define CPXERR_FAIL_OPEN_WRITE      1422
+#define CPXERR_BAD_FILETYPE         1424
+#define CPXERR_BAD_CTYPE            3021
+
+/* control parameters: */
+#define CPX_PARAM_ADVIND            1001
+#define CPX_PARAM_AGGIND            1003
+#define CPX_PARAM_DPRIIND           1009
+#define CPX_PARAM_EPOPT             1014
+#define CPX_PARAM_EPPER             1015
+#define CPX_PARAM_EPRHS             1016
+#define CPX_PARAM_FASTMIP           1017 /* ??? */
+#define CPX_PARAM_SIMDISPLAY        1019
+#define CPX_PARAM_ITLIM             1020
+#define CPX_PARAM_OBJLLIM           1025
+#define CPX_PARAM_OBJULIM           1026
+#define CPX_PARAM_PERIND            1027
+#define CPX_PARAM_PPRIIND           1029
+#define CPX_PARAM_PREIND            1030
+#define CPX_PARAM_REINV             1031
+#define CPX_PARAM_SCRIND            1035
+#define CPX_PARAM_DATACHECK         1056
+
+/* CPX_PARAM_DPRIIND: */
+#define CPX_DPRIIND_AUTO            0
+#define CPX_DPRIIND_FULL            1
+#define CPX_DPRIIND_STEEP           2
+#define CPX_DPRIIND_FULL_STEEP      3
+#define CPX_DPRIIND_STEEPQSTART     4
+#define CPX_DPRIIND_DEVEX           5
+
+/* CPX_PARAM_PPRIIND: */
+#define CPX_PPRIIND_PARTIAL         (-1)
+#define CPX_PPRIIND_AUTO            0
+#define CPX_PPRIIND_DEVEX           1
+#define CPX_PPRIIND_STEEP           2
+#define CPX_PPRIIND_STEEPQSTART     3
+#define CPX_PPRIIND_FULL            4
+
+/* CPXgetprobtype: */
+#define CPXPROB_LP                  0
+#define CPXPROB_MIP                 1
+#define CPXPROB_RELAXED             2
+#define CPXPROB_FIXED               3
+#define CPXPROB_QP                  5
+#define CPXPROB_ZEROEDQP            6
+
+/* CPXgetobjsen: */
+#define CPX_MIN                     1
+#define CPX_MAX                     (-1)
+
+/* CPXgetbase: */
+#define CPX_AT_LOWER                0
+#define CPX_BASIC                   1
+#define CPX_AT_UPPER                2
+#define CPX_FREE_SUPER              3
+
+/* CPXgetstat: */
+#define CPX_STAT_OPTIMAL            1
+#define CPX_STAT_UNBOUNDED          2
+#define CPX_STAT_INFEASIBLE         3
+#define CPX_STAT_INForUNBD          4
+#define CPX_STAT_OPTIMAL_INFEAS     5
+#define CPX_STAT_ABORT_IT_LIM       10
+#define CPX_STAT_ABORT_OBJ_LIM      12
+
+/* CPXgetmethod: */
+#define CPX_ALG_NONE                0
+#define CPX_ALG_PRIMAL              1
+#define CPX_ALG_DUAL                2
+#define CPX_ALG_BARRIER             4
+
+/* CPXsolninfo: */
+#define CPX_NO_SOLN                 0
+#define CPX_BASIC_SOLN              1
+#define CPX_NONBASIC_SOLN           2
+#define CPX_PRIMAL_SOLN             3
+
+int CPXaddcols(CPXENV *env, CPXLP *lp, int ccnt, int nzcnt,
+      const double obj[], const int cmatbeg[], const int cmatind[],
+      const double cmatval[], const double lb[], const double ub[],
+      char *colname[]);
+
+int CPXaddrows(CPXENV *env, CPXLP *lp, int ccnt, int rcnt, int nzcnt,
+      const double rhs[], const char sense[], const int rmatbeg[],
+      const int rmatind[], const double rmatval[], char *colname[],
+      char *rowname[]);
+
+int CPXbaropt(CPXENV *env, CPXLP *lp);
+
+int CPXbinvrow(CPXENV *env, CPXLP *lp, int i, double y[]);
+
+int CPXchgbds(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
+      const char lu[], const double bd[]);
+
+int CPXchgcoeflist(CPXENV *env, CPXLP *lp, int numcoefs,
+      const int rowlist[], const int collist[], const double vallist[]);
+
+void CPXchgobjsen(CPXENV *env, CPXLP *lp, int maxormin);
+
+int CPXchgsense(CPXENV *env, CPXLP *lp, int cnt, const int indices[],
+      const char sense[]);
+
+int CPXcloseCPLEX(CPXENV **env);
+
+int CPXcopybase(CPXENV *env, CPXLP *lp, const int cstat[],
+      const int rstat[]);
+
+int CPXcopybasednorms(CPXENV *env, CPXLP *lp, const int cstat[],
+      const int rstat[], const double dnorm[]);
+
+int CPXcopylp(CPXENV *env, CPXLP *lp, int numcols, int numrows,
+      int objsen, const double obj[], const double rhs[],
+      const char sense[], const int matbeg[], const int matcnt[],
+      const int matind[], const double matval[], const double lb[],
+      const double ub[], const double rngval[]);
+
+int CPXcopylpwnames(CPXENV *env, CPXLP *lp, int numcols, int numrows,
+      int objsen, const double obj[], const double rhs[],
+      const char sense[], const int matbeg[], const int matcnt[],
+      const int matind[], const double matval[], const double lb[],
+      const double ub[], const double rngval[], char *colname[],
+      char *rowname[]);
+
+CPXLP *CPXcreateprob(CPXENV *env, int *status, const char *probname);
+
+int CPXdelcols(CPXENV *env, CPXLP *lp, int begin, int end);
+
+int CPXdelrows(CPXENV *env, CPXLP *lp, int begin, int end);
+
+int CPXdelsetcols(CPXENV *env, CPXLP *lp, int delstat[]);
+
+int CPXdelsetrows(CPXENV *env, CPXLP *lp, int delstat[]);
+
+int CPXdualopt(CPXENV *env, CPXLP *lp);
+
+int CPXfreeprob(CPXENV *env, CPXLP **lp);
+
+int CPXgetbase(CPXENV *env, CPXLP *lp, int cstat[], int rstat[]);
+
+int CPXgetbasednorms(CPXENV *env, CPXLP *lp, int cstat[], int rstat[],
+      double dnorm[]);
+
+int CPXgetbhead(CPXENV *env, CPXLP *lp, int head[], double x[]);
+
+int CPXgetdblparam(CPXENV *env, int whichparam, double *value);
+
+int CPXgetdj(CPXENV *env, CPXLP *lp, double dj[], int begin, int end);
+
+char *CPXgeterrorstring(CPXENV *env, int errcode, char *buffer);
+
+int CPXgetijdiv(CPXENV *env, CPXLP *lp, int *idiv, int *jdiv);
+
+int CPXgetintparam(CPXENV *env, int whichparam, int *value);
+
+int CPXgetlb(CPXENV *env, CPXLP *lp, double lb[], int begin, int end);
+
+int CPXgetmethod(CPXENV *env, CPXLP *lp);
+
+int CPXgetnumcols(CPXENV *env, CPXLP *lp);
+
+int CPXgetnumnz(CPXENV *env, CPXLP *lp);
+
+int CPXgetnumrows(CPXENV *env, CPXLP *lp);
+
+int CPXgetobjval(CPXENV *env, CPXLP *lp, double *objval);
+
+int CPXgetpi(CPXENV *env, CPXLP *lp, double pi[], int begin, int end);
+
+int CPXgetsense(CPXENV *env, CPXLP *lp, char sense[], int begin,
+      int end);
+
+int CPXgetslack(CPXENV *env, CPXLP *lp, double slack[], int begin,
+      int end);
+
+int CPXgetstat(CPXENV *env, CPXLP *lp);
+
+int CPXgetub(CPXENV *env, CPXLP *lp, double ub[], int begin, int end);
+
+int CPXgetweight(CPXENV *env, CPXLP *lp, int rcnt, const int rmatbeg[],
+      const int rmatind[], const double rmatval[], double weight[],
+      int dpriind);
+
+int CPXgetx(CPXENV *env, CPXLP *lp, double x[], int begin, int end);
+
+int CPXinfodblparam(CPXENV *env, int whichparam, double *defvalue,
+      double *minvalue, double *maxvalue);
+
+int CPXinfointparam(CPXENV *env, int whichparam, int *defvalue,
+      int *minvalue, int *maxvalue);
+
+int CPXlpopt(CPXENV *env, CPXLP *lp);
+
+int CPXmdleave(const CPXENV *env, CPXLP *lp, const int goodlist[],
+      int goodlen, double downratio[], double upratio[]);
+
+int CPXnewcols(CPXENV *env, CPXLP *lp, int ccnt, const double obj[],
+      const double lb[], const double ub[], const char ctype[],
+      char *colname[]);
+
+int CPXnewrows(CPXENV *env, CPXLP *lp, int rcnt, const double rhs[],
+      const char sense[], const double rngval[], char *rowname[]);
+
+CPXENV *CPXopenCPLEX(int *status);
+
+int CPXpivotin(CPXENV *env, CPXLP *lp, const int rlist[], int rlen);
+
+int CPXpivotout(CPXENV *env, CPXLP *lp, const int clist[], int clen);
+
+int CPXprimopt(CPXENV *env, CPXLP *lp);
+
+int CPXsavwrite(CPXENV *env, CPXLP *lp, const char *filename);
+
+int CPXsetdblparam(CPXENV *env, int whichparam, double newvalue);
+
+int CPXsetintparam(CPXENV *env, int whichparam, int newvalue);
+
+int CPXsolninfo(CPXENV *env, CPXLP *lp, int *solnmethod, int *solntype,
+      int *pfeasind, int *dfeasind);
+
+int CPXsolution(CPXENV *env, CPXLP *lp, int *lpstat, double *objval,
+      double x[], double pi[], double slack[], double dj[]);
+
+int CPXstrongbranch(CPXENV *env, CPXLP *lp, const int goodlist[],
+      int goodlen, double downpen[], double uppen[], int itlim);
+
+int CPXwriteprob(CPXENV *env, CPXLP *lp, const char *filename,
+      const char *filetype);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* eof */
Index: deps/glpk/examples/cpp.mod
===================================================================
--- deps/glpk/examples/cpp.mod	(revision 9)
+++ deps/glpk/examples/cpp.mod	(revision 9)
@@ -0,0 +1,67 @@
+/* CPP, Critical Path Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* Note: Reduced costs of auxiliary variables phi[j,k] (see below)
+         can be only zero or one. The critical path is defined by the
+         constraints, whose reduced cost is one. */
+
+set J;
+/* set of jobs (activities) */
+
+set P{j in J}, in J, default {};
+/* P[j] is a subset of jobs that immediately precede job j */
+
+param t{j in J}, >= 0;
+/* duration required to perform job j */
+
+var x{j in J}, >= 0;
+/* starting time of job j */
+
+s.t. phi{j in J, k in P[j]}: x[j] >= x[k] + t[k];
+/* job j can start only after all immediately preceding jobs have been
+   completely performed */
+
+var z;
+/* project makespan */
+
+s.t. fin{j in J}: z >= x[j] + t[j];
+/* which is the maximum of the completion times of all the jobs */
+
+minimize obj: z;
+/* the objective is make z as small as possible */
+
+data;
+
+/* The optimal solution is 46 */
+
+param : J :  t :=
+        A    3    /* Excavate */
+        B    4    /* Lay foundation */
+        C    3    /* Rough plumbing */
+        D   10    /* Frame */
+        E    8    /* Finish exterior */
+        F    4    /* Install HVAC */
+        G    6    /* Rough electric */
+        H    8    /* Sheet rock */
+        I    5    /* Install cabinets */
+        J    5    /* Paint */
+        K    4    /* Final plumbing */
+        L    2    /* Final electric */
+        M    4    /* Install flooring */
+;
+
+set P[B] := A;
+set P[C] := B;
+set P[D] := B;
+set P[E] := D;
+set P[F] := D;
+set P[G] := D;
+set P[H] := C E F G;
+set P[I] := H;
+set P[J] := H;
+set P[K] := I;
+set P[L] := J;
+set P[M] := K L;
+
+end;
Index: deps/glpk/examples/crypto.mod
===================================================================
--- deps/glpk/examples/crypto.mod	(revision 9)
+++ deps/glpk/examples/crypto.mod	(revision 9)
@@ -0,0 +1,84 @@
+/* CRYPTO, a crypto-arithmetic puzzle */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* This problem comes from the newsgroup rec.puzzle.
+   The numbers from 1 to 26 are assigned to the letters of the alphabet.
+   The numbers beside each word are the total of the values assigned to
+   the letters in the word (e.g. for LYRE: L, Y, R, E might be to equal
+   5, 9, 20 and 13, or any other combination that add up to 47).
+   Find the value of each letter under the equations:
+
+   BALLET  45     GLEE  66     POLKA      59     SONG     61
+   CELLO   43     JAZZ  58     QUARTET    50     SOPRANO  82
+   CONCERT 74     LYRE  47     SAXOPHONE 134     THEME    72
+   FLUTE   30     OBOE  53     SCALE      51     VIOLIN  100
+   FUGUE   50     OPERA 65     SOLO       37     WALTZ    34
+
+   Solution:
+   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
+   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
+
+   Reference:
+   Koalog Constraint Solver <http://www.koalog.com/php/jcs.php>,
+   Simple problems, the crypto-arithmetic puzzle ALPHACIPHER. */
+
+set LETTERS :=
+{     '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'
+};
+/* set of letters */
+
+set VALUES := 1..card(LETTERS);
+/* set of values assigned to the letters */
+
+set WORDS;
+/* set of words */
+
+param total{word in WORDS};
+/* total[word] is the total of the values assigned to the letters in
+   the word */
+
+var x{i in LETTERS, j in VALUES}, binary;
+/* x[i,j] = 1 means that letter i is assigned value j */
+
+s.t. phi{i in LETTERS}: sum{j in VALUES} x[i,j] = 1;
+
+s.t. psi{j in VALUES}: sum{i in LETTERS} x[i,j] = 1;
+
+s.t. eqn{word in WORDS}: sum{k in 1..length(word), j in VALUES}
+      j * x[substr(word,k,1), j] = total[word];
+
+solve;
+
+printf{i in LETTERS} "  %s", i;
+printf "\n";
+
+printf{i in LETTERS} " %2d", sum{j in VALUES} j * x[i,j];
+printf "\n";
+
+data;
+
+param :  WORDS :   total :=
+         BALLET       45
+         CELLO        43
+         CONCERT      74
+         FLUTE        30
+         FUGUE        50
+         GLEE         66
+         JAZZ         58
+         LYRE         47
+         OBOE         53
+         OPERA        65
+         POLKA        59
+         QUARTET      50
+         SAXOPHONE   134
+         SCALE        51
+         SOLO         37
+         SONG         61
+         SOPRANO      82
+         THEME        72
+         VIOLIN      100
+         WALTZ        34 ;
+
+end;
Index: deps/glpk/examples/csv/distances.csv
===================================================================
--- deps/glpk/examples/csv/distances.csv	(revision 9)
+++ deps/glpk/examples/csv/distances.csv	(revision 9)
@@ -0,0 +1,7 @@
+plant,market,distance
+"Seattle","New York",2.5
+"Seattle","Chicago",1.7
+"Seattle","Topeka",1.8
+"San Diego","New York",2.5
+"San Diego","Chicago",1.8
+"San Diego","Topeka",1.4
Index: deps/glpk/examples/csv/markets.csv
===================================================================
--- deps/glpk/examples/csv/markets.csv	(revision 9)
+++ deps/glpk/examples/csv/markets.csv	(revision 9)
@@ -0,0 +1,4 @@
+market,demand
+"New York",325.
+"Chicago",300.
+"Topeka",275.
Index: deps/glpk/examples/csv/parameters.csv
===================================================================
--- deps/glpk/examples/csv/parameters.csv	(revision 9)
+++ deps/glpk/examples/csv/parameters.csv	(revision 9)
@@ -0,0 +1,2 @@
+parameter,value
+"transport cost",90.
Index: deps/glpk/examples/csv/plants.csv
===================================================================
--- deps/glpk/examples/csv/plants.csv	(revision 9)
+++ deps/glpk/examples/csv/plants.csv	(revision 9)
@@ -0,0 +1,3 @@
+plant,capacity
+"Seattle",350.
+"San Diego",600.
Index: deps/glpk/examples/csv/transp_csv.mod
===================================================================
--- deps/glpk/examples/csv/transp_csv.mod	(revision 9)
+++ deps/glpk/examples/csv/transp_csv.mod	(revision 9)
@@ -0,0 +1,70 @@
+# A TRANSPORTATION PROBLEM
+#
+# This problem finds a least cost shipping schedule that meets
+# requirements at markets and supplies at factories.
+#
+#  References:
+#              Dantzig G B, "Linear Programming and Extensions."
+#              Princeton University Press, Princeton, New Jersey, 1963,
+#              Chapter 3-3.
+
+set I;
+/* canning plants */
+
+set J;
+/* markets */
+
+set K dimen 2;
+/* transportation lane */
+
+set L;
+/* parameters */
+
+param a{i in I};
+/* capacity of plant i in cases */
+
+param b{j in J};
+/* demand at market j in cases */
+
+param d{i in I, j in J};
+/* distance in thousands of miles */
+
+param e{l in L};
+/* parameters */
+
+param f;
+/* freight in dollars per case per thousand miles */
+
+table tab_plant IN "CSV" "plants.csv" :
+  I <- [plant], a ~ capacity;
+
+table tab_market IN "CSV" "markets.csv" :
+  J <- [market], b ~ demand;
+
+table tab_distance IN "CSV" "distances.csv" :
+  K <- [plant, market], d ~ distance;
+
+table tab_parameter IN "CSV" "parameters.csv" :
+  L <- [parameter], e ~ value ;
+
+param c{i in I, j in J} := e['transport cost'] * d[i,j] / 1000;
+/* transport cost in thousands of dollars per case */
+
+var x{(i,j) in K} >= 0;
+/* shipment quantities in cases */
+
+minimize cost: sum{(i,j) in K} c[i,j] * x[i,j];
+/* total transportation costs in thousands of dollars */
+
+s.t. supply{i in I}: sum{(i,j) in K} x[i,j] <= a[i];
+/* observe supply limit at plant i */
+
+s.t. demand{j in J}: sum{(i,j) in K} x[i,j] >= b[j];
+/* satisfy demand at market j */
+
+solve;
+
+table tab_result{(i,j) in K} OUT "CSV" "result.csv" :
+  i ~ plant, j ~ market, x[i,j] ~ shipment;
+
+end;
Index: deps/glpk/examples/dbf/ForestMgt_Model_I_GIS_dbf.mod
===================================================================
--- deps/glpk/examples/dbf/ForestMgt_Model_I_GIS_dbf.mod	(revision 9)
+++ deps/glpk/examples/dbf/ForestMgt_Model_I_GIS_dbf.mod	(revision 9)
@@ -0,0 +1,226 @@
+#  Model I Forest Estate Modelling using GLPK/MathProg
+#  Reading and writing dbf files
+
+#  by Noli Sicad --- nsicad@gmail.com
+# 18 December 2009
+
+#  Forest Management 4th Edition 
+#  by Lawrence Davis, K. Norman Johnson, Pete Bettinger, Theodore Howard
+#  Chapter 11 - Daniel Pickett 
+#  http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
+
+#  Model I Formulation
+
+/*  Note: This is not the full LP model mentioned in the book.
+Some of the constraints are deliberately omitted in this model for the purpose of clarity.
+
+The features of MathProg in this example are:
+* reading and writing dbf from regular dbf files,
+* reading dbf file (database of shapefile (stands.shp)) (e.g. area parameter),
+* using the area data in the constraints and
+* writing dbf file from result of LP model.
+
+Model I - Harvest Scheduling formulation for Sustainable Forest Management (SFM)
+
+Features are:
+* Net Present Value for the objective function (Revenue - Cost)
+* Harvest Constraints by period - Sustainable Yield per Period
+* Even-Flow Constraint / Volume - Harvest Flow Constraint -  Alpha (1-Apha)
+* Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta  (1 +Beta)
+* Forest / Land Constraint -- Total Area of the forest
+* Forest Stand Constraint  -- Individual stands
+
+What is next? -- Forest Mgt Carbon Accounting for Climate Change
+
+Note: The model file that the data containing in
+the dbf files is public domain material (so it is compatible with the
+GNU GPL) and data can be found in 
+http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
+
+# Noli Sicad --- nsicad@gmail.com
+
+*/
+
+set G_STAND_TYPE; # A, B, C
+
+set I_CULTURAL_PRES; 
+set J_MGT_YEAR; 
+
+param K_PERIOD;
+param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR}; # cost
+
+param Yield_Table_Vol{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
+
+
+param Alpha >= 0;
+param Beta >= 0;
+
+param TCost_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
+
+param NetRev_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD};
+
+
+var XForestLand{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} >= 0;
+
+
+#reading dbf tables
+table tab IN "xBASE" "standtype.dbf": G_STAND_TYPE <- [STAND];
+display G_STAND_TYPE;
+
+
+table tab2 IN "xBASE" "cultural_pres.dbf": I_CULTURAL_PRES <- [CUL_PRES];
+display I_CULTURAL_PRES;
+
+table tab3 IN "xBASE" "mgt_year.dbf": J_MGT_YEAR <- [MGT_YEAR];
+display J_MGT_YEAR;
+
+/*
+param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR} default 0; # cost
+*/
+
+set S1, dimen 3;
+table tab4 IN "xBASE" "Forest_Cost.dbf": S1 <- [STAND, CUL_PRES, MGT_YEAR],Forest_Cost ~FCOST;
+display Forest_Cost;
+
+set S2, dimen 4;
+table tab5 IN "xBASE" "Yield_Table_Vol.dbf": S2 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],Yield_Table_Vol ~YIELD;
+display Yield_Table_Vol;
+
+set S3, dimen 4;
+table tab5 IN "xBASE" "TCost_Table.dbf": S3 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],TCost_Table ~TCOST;
+display TCost_Table;
+
+
+set S4, dimen 4;
+table tab5 IN "xBASE" "NetRev_Table.dbf": S4 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],NetRev_Table ~NETREV;
+display NetRev_Table;
+
+
+param MGT;
+
+param Area_Stand_Indi{g in G_STAND_TYPE, m in 1..MGT} default 0; 
+
+set ST, dimen 2;
+table tab5 IN "xBASE" "stands.dbf": ST <- [VEG_TYPE, MGT], Area_Stand_Indi ~ACRES;
+display Area_Stand_Indi;
+
+param Area_Stand_Type{g in G_STAND_TYPE}:= sum {m in 1..MGT } Area_Stand_Indi[g,m];
+display Area_Stand_Type;
+
+
+param Total_Area := sum {g in G_STAND_TYPE, m in 1..MGT } Area_Stand_Indi[g,m];
+display Total_Area;
+
+param Harvest_Min_Vol_Period;
+
+
+var NetPresentValue;
+
+# Objective function
+maximize Net_Present_Value: NetPresentValue;
+
+subject to NPV:
+   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];
+
+# Harvest Constraint by Period
+subject to Harvest_Period_H {k in 1..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] >= Harvest_Min_Vol_Period;
+   
+
+#Even-Flow Constraint / Volume - Harvest Flow Constraint - Alpha
+subject to Even_Flow_Constaints_Alpha {k in 6..K_PERIOD-1}:
+    (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;
+
+# Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta
+subject to Even_Flow_Constaints_Beta {k in 6..K_PERIOD-1}:
+    (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] -
+    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;
+   
+# Forest / Land Constraints
+subject to Total_Area_Constraint: 
+  sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} XForestLand[g,i,j] <= Total_Area;
+display Total_Area;   
+
+# Forest / Land Constraints for A B C
+subject to Area {g in G_STAND_TYPE}:
+   sum {i in I_CULTURAL_PRES,j in J_MGT_YEAR} XForestLand[g,i,j] = Area_Stand_Type[g];
+
+
+
+solve;
+#RESULT SECTION
+printf '#################################\n';
+printf 'Forest Management Model I - Noli Sicad\n';
+printf '\n';
+printf 'Net Present Value = %.2f\n', NetPresentValue;
+printf '\n';
+
+printf '\n';
+printf 'Variables\n';
+printf 'Stand_Type  Age_Class  Mgt_Presc  Sign Value \n';
+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]; 
+printf '\n';
+
+printf 'Constraints\n';
+printf 'Period Harvest Sign \n';
+for {k in 1..K_PERIOD} {
+ 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;
+   }
+
+# xbase (dbf) output
+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;
+
+# xbase (dbf) read
+set S, dimen 2;
+table tab2 IN "xBASE" "HarvestArea1.dbf": S <- [Period, H_Area];
+display S;
+
+
+
+
+printf '\n';
+printf 'Constraint\n';
+printf 'Harvest Period\n';
+printf 'Type AgeClass  PrescMgt Period    Value\n';
+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]); 
+
+
+printf 'Even_Flow_Constaint_Alpha (1-Alpha)\n';
+printf 'Period Sign \n';
+for {k in 6..K_PERIOD-1} {
+   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;
+  }
+printf '\n';
+
+
+# Forest / Land Constraints
+printf '\n';  
+printf 'Total Area Constraint\n';
+printf 'Type AgeClass  PrescMgt  Value Sign Total_Area \n';
+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;
+
+printf 'Area\n';
+printf 'Area Value Sign Areas_Stand\n';
+for {g in G_STAND_TYPE} {
+  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];
+   }
+
+
+#DATA SECTION 
+      
+data;
+
+# Most of the data has been moved to dbf format
+
+param MGT:=31;
+
+param K_PERIOD:= 7;
+
+param Alpha:= 0.20;
+param Beta:= 0.20;
+
+param Harvest_Min_Vol_Period:= 12000;
+
+end;
+
Index: deps/glpk/examples/dbf/README
===================================================================
--- deps/glpk/examples/dbf/README	(revision 9)
+++ deps/glpk/examples/dbf/README	(revision 9)
@@ -0,0 +1,2 @@
+This subdirectory contains an example MathProg model that demonstrates
+using data tables in DBF format.
Index: deps/glpk/examples/dea.mod
===================================================================
--- deps/glpk/examples/dea.mod	(revision 9)
+++ deps/glpk/examples/dea.mod	(revision 9)
@@ -0,0 +1,222 @@
+/* Data Envelopment Analysis (DEA)
+ *
+ * DEA quantifies the relative efficiency of decision making units (DMUs) by
+ * finding the efficient frontier in multiple input multiple output data.  The
+ * inputs are resources (eg. number of employees, available machines, ...),
+ * the outputs are productive outputs (eg. contracts made, total sales, ...).
+ * The method is non-parametric.  More details are available in the paper
+ * below.
+ *
+ * Models according to: Seiford, Threall, "Recent developments in DEA", 1990.
+ *
+ * Implementation: Sebastian Nowozin <nowozin@gmail.com>
+ */
+
+### SETS ###
+
+set dmus;       # Decision Making Units (DMU)
+set inputs;     # Input parameters
+set outputs;    # Output parameters
+
+
+### PARAMETERS ###
+
+param input_data{dmus,inputs} >= 0;
+param output_data{dmus,outputs} >= 0;
+
+
+### PROGRAM ###
+
+var theta{dmus} >= 0;
+var lambda{dmus,dmus} >= 0;
+
+minimize inefficiency: sum{td in dmus} theta[td];
+
+s.t. output_lower_limit{o in outputs, td in dmus}:
+    sum{d in dmus} lambda[d,td]*output_data[d,o] >= output_data[td,o];
+s.t. input_upper_limit{i in inputs, td in dmus}:
+    sum{d in dmus} lambda[d,td]*input_data[d,i] <= theta[td]*input_data[td,i];
+
+    s.t. PI1{td in dmus}:
+        sum{d in dmus} lambda[d,td] = 1;
+/*
+possibilities:
+      i) (no constraint)
+     ii) s.t. PI1{td in dmus}:
+        sum{d in dmus} lambda[d,td] <= 1;
+    iii) s.t. PI1{td in dmus}:
+        sum{d in dmus} lambda[d,td] >= 1;
+*/
+
+
+### SOLVE AND PRINT SOLUTION ###
+
+solve;
+
+printf "DMU\tEfficiency\n";
+for {td in dmus} {
+    printf "%s\t%1.4f\n", td, theta[td];
+}
+
+### DATA ###
+
+data;
+
+set dmus := 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+    21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
+    41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
+    61 62 63 64 65 66 67 68 69 ;
+set inputs := AvgInventory LaborCost OperatingCost Population ;
+set outputs := PrescrVol kDollarValue ;
+
+param input_data default 0.0 :
+
+        AvgInventory LaborCost OperatingCost Population :=
+
+1 8000 17030 1280 1410
+2 9000 25890 2779 1523
+3 13694 29076 2372 1354
+4 4250 17506 1385 822
+5 6500 23208 639 746
+6 7000 12946 802 1281
+7 4500 18001 1130 1016
+8 5000 14473 1097 1070
+9 27000 31760 5559 1694
+10 21560 50972 15010 1910
+11 15000 39523 4799 1745
+12 8500 13076 3489 1353
+13 35000 35427 1704 500
+14 18000 27554 2882 1016
+15 59750 53848 14208 2500
+16 19200 38253 1480 2293
+17 40000 109404 83016 2718
+18 8466 18198 1278 2877
+19 16000 40891 7599 4150
+20 10000 45444 5556 4421
+21 25000 35623 2121 3883
+22 14000 20192 5515 3519
+23 12500 34973 10475 32366
+24 17260 32284 14498 3393
+25 7000 17920 7585 4489
+26 14000 42094 3742 2217
+27 16400 35422 14236 4641
+28 13000 19100 3529 5968
+29 30000 72167 8656 8715
+30 12530 19970 1714 5968
+31 31500 39183 4919 5607
+32 10000 32048 3483 7324
+33 22000 68877 12279 8685
+34 10000 29812 3332 8685
+35 16000 47686 2507 5420
+36 10000 33415 4738 7703
+37 9000 12359 4603 4665
+38 16439 23614 2989 6317
+39 14500 36069 1793 31839
+40 39000 76307 9539 15619
+41 24927 40706 12661 30213
+42 13858 39267 4609 34719
+43 33375 29509 11323 31839
+44 29044 44482 5542 34719
+45 32257 61365 20550 32366
+46 8800 49671 3306 43561
+47 47000 40425 10396 31263
+48 12000 33034 4915 31263
+49 28000 69163 4688 15173
+50 13300 28931 16735 73064
+51 13500 29758 4260 62309
+52 24000 40927 8285 23166
+53 16000 40403 2131 99836
+54 17000 38730 2539 60348
+55 25000 35978 2502 99836
+56 16000 37509 6278 99836
+57 20000 46950 10715 85925
+58 14000 35966 3144 85925
+59 22000 68318 8015 108987
+60 21879 69537 7778 108987
+61 15000 25425 2812 201404
+62 10000 19508 2454 201404
+63 20000 28191 3367 201404
+64 18000 37073 8624 108987
+65 19051 23763 3496 201404
+66 15000 28642 3366 201404
+67 10000 35919 3868 201404
+68 24000 54653 26494 108987
+69 1800 6276 3413 60348
+        ;
+
+param output_data default 0.0 :
+
+        PrescrVol kDollarValue :=
+
+1 12293 61.00
+2 18400 92.00
+3 16789 92.65
+4 10700 45.00
+5 9800 50.00
+6 6500 29.00
+7 8200 56.00
+8 8680 45.00
+9 33800 183.00
+10 23710 156.00
+11 24000 120.00
+12 17500 75.00
+13 25000 130.00
+14 26000 122.00
+15 26830 178.513
+16 16600 106.00
+17 90000 450.00
+18 11140 73.624
+19 25868 136.00
+20 32700 191.295
+21 29117 152.864
+22 18000 100.00
+23 11100 60.00
+24 23030 137.778
+25 10656 58.00
+26 24682 152.095
+27 26908 120.00
+28 16464 80.00
+29 57000 321.00
+30 17532 94.747
+31 30035 168.00
+32 16000 100.00
+33 63700 277.00
+34 18000 90.00
+35 27339 139.134
+36 19500 116.00
+37 13000 80.00
+38 15370 102.00
+39 18446 90.00
+40 56000 260.00
+41 73845 364.951
+42 28600 145.00
+43 27000 243.00
+44 52423 279.816
+45 73759 363.388
+46 20500 80.00
+47 27100 115.00
+48 15000 110.00
+49 50895 277.852
+50 19707 128.00
+51 17994 78.80
+52 36135 167.222
+53 30000 153.00
+54 26195 125.00
+55 28000 216.00
+56 24658 152.551
+57 36850 190.00
+58 29250 183.69
+59 50000 250.00
+60 40078 265.443
+61 20200 110.00
+62 12500 75.00
+63 30890 195.00
+64 31000 175.00
+65 31277 192.992
+66 11500 75.00
+67 30000 175.668
+68 38383 190.00
+69 2075 8.650
+        ;
+
+end;
Index: deps/glpk/examples/diet.mod
===================================================================
--- deps/glpk/examples/diet.mod	(revision 9)
+++ deps/glpk/examples/diet.mod	(revision 9)
@@ -0,0 +1,99 @@
+# STIGLER'S NUTRITION MODEL
+#
+# This model determines a least cost diet which meets the daily
+# allowances of nutrients for a moderately active man weighing 154 lbs.
+#
+#  References:
+#              Dantzig G B, "Linear Programming and Extensions."
+#              Princeton University Press, Princeton, New Jersey, 1963,
+#              Chapter 27-1.
+
+set N;
+/* nutrients */
+
+set F;
+/* foods */
+
+param b{N};
+/* required daily allowances of nutrients */
+
+param a{F,N};
+/* nutritive value of foods (per dollar spent) */
+
+var x{f in F} >= 0;
+/* dollars of food f to be purchased daily */
+
+s.t. nb{n in N}: sum{f in F} a[f,n] * x[f] = b[n];
+/* nutrient balance (units) */
+
+minimize cost: sum{f in F} x[f];
+/* total food bill (dollars) */
+
+data;
+
+param : N : b :=
+         Calorie       3 /* thousands */
+         Protein      70 /* grams */
+         Calcium     0.8 /* grams */
+         Iron         12 /* milligrams */
+         Vitamin-A     5 /* thousands IUs */
+         Vitamin-B1  1.8 /* milligrams */
+         Vitamin-B2  2.7 /* milligrams */
+         Niacin       18 /* milligrams */
+         Vitamin-C    75 /* milligrams */  ;
+
+set F := Wheat Cornmeal Cannedmilk Margarine Cheese Peanut-B Lard
+         Liver Porkroast Salmon Greenbeans Cabbage Onions Potatoes
+         Spinach Sweet-Pot Peaches Prunes Limabeans Navybeans;
+
+param a default 0
+
+:           Calorie  Protein  Calcium  Iron  Vitamin-A  Vitamin-B1 :=
+#            (1000)    (g)      (g)    (mg)   (1000IU)     (mg)
+
+Wheat         44.7     1411      2.0    365        .       55.4
+Cornmeal      36        897      1.7     99      30.9      17.4
+Cannedmilk     8.4      422     15.1      9      26         3
+Margarine     20.6       17       .6      6      55.8        .2
+Cheese         7.4      448     16.4     19      28.1        .8
+Peanut-B      15.7      661      1       48        .        9.6
+Lard          41.7        .       .       .        .2        .
+Liver          2.2      333       .2    139     169.2       6.4
+Porkroast      4.4      249       .3     37        .       18.2
+Salmon         5.8      705      6.8     45       3.5       1
+Greenbeans     2.4      138      3.7     80      69         4.3
+Cabbage        2.6      125      4       36       7.2       9
+Onions         5.8      166      3.8     59      16.6       4.7
+Potatoes      14.3      336      1.8    118       6.7      29.4
+Spinach        1.1      106       .     138     918.4       5.7
+Sweet-Pot      9.6      138      2.7     54     290.7       8.4
+Peaches        8.5       87      1.7    173      86.8       1.2
+Prunes        12.8       99      2.5    154      85.7       3.9
+Limabeans     17.4     1055      3.7    459       5.1      26.9
+Navybeans     26.9     1691     11.4    792        .       38.4
+
+:          Vitamin-B2  Niacin  Vitamin-C :=
+#             (mg)      (mg)     (mg)
+
+Wheat         33.3       441         .
+Cornmeal       7.9       106         .
+Cannedmilk    23.5        11        60
+Margarine       .          .         .
+Cheese        10.3         4         .
+Peanut-B       8.1       471         .
+Lard            .5         5         .
+Liver         50.8       316       525
+Porkroast      3.6        79         .
+Salmon         4.9       209         .
+Greenbeans     5.8        37       862
+Cabbage        4.5        26      5369
+Onions         5.9        21      1184
+Potatoes       7.1       198      2522
+Spinach       13.8        33      2755
+Sweet-Pot      5.4        83      1912
+Peaches        4.3        55        57
+Prunes         4.3        65       257
+Limabeans     38.2        93         .
+Navybeans     24.6       217         .   ;
+
+end;
Index: deps/glpk/examples/dist.mod
===================================================================
--- deps/glpk/examples/dist.mod	(revision 9)
+++ deps/glpk/examples/dist.mod	(revision 9)
@@ -0,0 +1,565 @@
+# DIST, a product distribution model
+#
+# References:
+# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
+# for Mathematical Programming." Management Science 36 (1990) 519-554.
+
+###  SHIPPING SETS AND PARAMETERS  ###
+
+set whse 'warehouses';  # Locations from which demand is satisfied
+
+set dctr 'distribution centers' within whse;
+
+                        # Locations from which product may be shipped
+
+param sc 'shipping cost' {dctr,whse} >= 0;
+
+                        # Shipping costs, to whse from dctr, in $ / 100 lb
+
+param huge 'largest shipping cost' > 0;
+
+                        # Largest cost allowed for a usable shipping route
+
+param msr 'minimum size restriction' {dctr,whse} logical;
+
+                        # True indicates a minimum-size restriction on
+                        # direct shipments using this dctr --> whse route
+
+param dsr 'direct shipment requirement' {dctr} >= 0;
+
+                        # Minimum total demand, in pallets, needed to
+                        # allow shipment on routes subject to the
+                        # minimum size restriction
+
+###  PLANT SETS AND PARAMETERS  ###
+
+set fact 'factories' within dctr;
+
+                        # Locations where product is manufactured
+
+param rtmin 'regular-time total minimum' >= 0;
+
+                        # Lower limit on (average) total regular-time
+                        # crews employed at all factories
+
+param rtmax 'regular-time total maximum' >= rtmin;
+
+                        # Upper limit on (average) total regular-time
+                        # crews employed at all factories
+
+param otmin 'overtime total minimum' >= 0;
+
+                        # Lower limit on total overtime hours at all factories
+
+param otmax 'overtime total maximum' >= otmin;
+
+                        # Upper limit on total overtime hours at all factories
+
+param rmin 'regular-time minimums' {fact} >= 0;
+
+                        # Lower limits on (average) regular-time crews
+
+param rmax 'regular-time maximums' {f in fact} >= rmin[f];
+
+                        # Upper limits on (average) regular-time crews
+
+param omin 'overtime minimums' {fact} >= 0;
+
+                        # Lower limits on overtime hours
+
+param omax 'overtime maximums' {f in fact} >= omin[f];
+
+                        # Upper limits on overtime hours
+
+param hd 'hours per day' {fact} >= 0;
+
+                        # Regular-time hours per working day
+
+param dp 'days in period' {fact} > 0;
+
+                        # Working days in the current planning period
+
+###  PRODUCT SETS AND PARAMETERS  ###
+
+set prd 'products';     # Elements of the product group
+
+param wt 'weight' {prd} > 0;
+
+                        # Weight in 100 lb / 1000 cases
+
+param cpp 'cases per pallet' {prd} > 0;
+
+                        # Cases of product per shipping pallet
+
+param tc 'transshipment cost' {prd} >= 0;
+
+                        # Transshipment cost in $ / 1000 cases
+
+param pt 'production time' {prd,fact} >= 0;
+
+                        # Crew-hours to produce 1000 cases
+
+param rpc 'regular-time production cost' {prd,fact} >= 0;
+
+                        # Cost of production on regular time,
+                        # in $ / 1000 cases
+
+param opc 'overtime production cost' {prd,fact} >= 0;
+
+                        # Cost of production on overtime, in $ / 1000 cases
+
+###  DEMAND SETS AND PARAMETERS  ###
+
+param dt 'total demand' {prd} >= 0;
+
+                        # Total demands for products, in 1000s
+
+param ds 'demand shares' {prd,whse} >= 0.0, <= 1.0;
+
+                        # Historical demand data, from which each
+                        # warehouse's share of total demand is deduced
+
+param dstot {p in prd} := sum {w in whse} ds[p,w];
+
+                        # Total of demand shares; should be 1, but often isn't
+
+param dem 'demand' {p in prd, w in whse} := dt[p] * ds[p,w] / dstot[p];
+
+                        # Projected demands to be satisfied, in 1000s
+
+set rt 'shipping routes available' :=
+
+ {d in dctr, w in whse:
+         d <> w  and  sc[d,w] < huge  and
+         (w in dctr or sum {p in prd} dem[p,w] > 0)  and
+         not (msr[d,w] and sum {p in prd} 1000*dem[p,w]/cpp[p] < dsr[d]) };
+
+                        # List of ordered pairs that represent routes
+                        # on which shipments are allowed
+
+###  VARIABLES  ###
+
+var Rprd 'regular-time production' {prd,fact} >= 0;
+
+                        # Regular-time production of each product
+                        # at each factory, in 1000s of cases
+
+var Oprd 'overtime production' {prd,fact} >= 0;
+
+                        # Overtime production of each product
+                        # at each factory, in 1000s of cases
+
+var Ship 'shipments' {prd,rt} >= 0;
+
+                        # Shipments of each product on each allowed route,
+                        # in 1000s of cases
+
+var Trans 'transshipments' {prd,dctr} >= 0;
+
+                        # Transshipments of each product at each
+                        # distribution center, in 1000s of cases
+
+###  OBJECTIVE  ###
+
+minimize cost:  sum {p in prd, f in fact} rpc[p,f] * Rprd[p,f] +
+                sum {p in prd, f in fact} opc[p,f] * Oprd[p,f] +
+                sum {p in prd, (d,w) in rt} sc[d,w] * wt[p] * Ship[p,d,w] +
+                sum {p in prd, d in dctr} tc[p] * Trans[p,d];
+
+                        # Total cost:  regular production, overtime
+                        # production, shipping, and transshipment
+
+###  CONSTRAINTS  ###
+
+rtlim 'regular-time total limits':
+
+    rtmin <= sum {p in prd, f in fact}
+                        (pt[p,f] * Rprd[p,f]) / (dp[f] * hd[f]) <= rtmax;
+
+                        # Total crews must lie between limits
+
+otlim 'overtime total limits':
+
+    otmin <= sum {p in prd, f in fact} pt[p,f] * Oprd[p,f] <= otmax;
+
+                        # Total overtime must lie between limits
+
+rlim 'regular-time limits' {f in fact}:
+
+    rmin[f] <= sum {p in prd}
+                        (pt[p,f] * Rprd[p,f]) / (dp[f] * hd[f]) <= rmax[f];
+
+                        # Crews at each factory must lie between limits
+
+olim 'overtime limits' {f in fact}:
+
+    omin[f] <= sum {p in prd} pt[p,f] * Oprd[p,f] <= omax[f];
+
+                        # Overtime at each factory must lie between limits
+
+noRprd 'no regular production' {p in prd, f in fact: rpc[p,f] = 0}:
+
+    Rprd[p,f] = 0;
+
+noOprd 'no overtime production' {p in prd, f in fact: opc[p,f] = 0}:
+
+    Oprd[p,f] = 0;      # Do not produce where specified cost is zero
+
+bal 'material balance' {p in prd, w in whse}:
+
+    sum {(v,w) in rt}
+       Ship [p,v,w] + (if w in fact then Rprd[p,w] + Oprd[p,w]) =
+
+    dem[p,w] + (if w in dctr then sum {(w,v) in rt} Ship[p,w,v]);
+
+                        # Demand is satisfied by shipment into warehouse
+                        # plus production (if it is a factory)
+                        # minus shipment out (if it is a distn. center)
+
+trdef 'transshipment definition' {p in prd, d in dctr}:
+
+    Trans[p,d] >= sum {(d,w) in rt} Ship [p,d,w] -
+                  (if d in fact then Rprd[p,d] + Oprd[p,d]);
+
+                        # Transshipment at a distribution center is
+                        # shipments out less production (if any)
+
+###  DATA -- 3 PRODUCTS  ###
+
+data;
+
+set prd := 18REG 24REG 24PRO ;
+
+set whse := w01 w02 w03 w04 w05 w06 w08 w09 w12 w14 w15 w17
+            w18 w19 w20 w21 w24 w25 w26 w27 w28 w29 w30 w31
+            w32 w33 w34 w35 w36 w37 w38 w39 w40 w41 w42 w43
+            w44 w45 w46 w47 w48 w49 w50 w51 w53 w54 w55 w56
+            w57 w59 w60 w61 w62 w63 w64 w65 w66 w68 w69 w71
+            w72 w73 w74 w75 w76 w77 w78 w79 w80 w81 w82 w83
+            w84 w85 w86 w87 w89 w90 w91 w92 w93 w94 w95 w96
+            w98 x22 x23 ;
+
+set dctr := w01 w02 w03 w04 w05 w62 w76 w96 ;
+
+set fact := w01 w05 w96 ;
+
+param huge := 99. ;
+
+param rtmin := 0.0 ;
+param rtmax := 8.0 ;
+
+param otmin :=  0.0 ;
+param otmax := 96.0 ;
+
+param rmin  :=  w01 0.00   w05 0.00   w96 0.00 ;
+param rmax  :=  w01 3.00   w05 2.00   w96 3.00 ;
+
+param omin  :=  w01  0.0   w05  0.0   w96  0.0 ;
+param omax  :=  w01 48.0   w05  0.0   w96 48.0 ;
+
+param hd    :=  w01  8.0   w05  8.0   w96  8.0 ;
+
+param dp    :=  w01 19.0   w05 19.0   w96 19.0 ;
+
+param wt  :=  18REG  47.3    24REG  63.0    24PRO  63.0 ;
+
+param tc  :=  18REG  40.00   24REG  45.00   24PRO  45.00 ;
+
+param dt  :=  18REG 376.0    24REG 172.4    24PRO 316.3 ;
+
+param cpp :=  18REG 102.     24REG  91.     24PRO  91. ;
+
+param dsr := w01 96.  w02 96.  w03 96.  w04 96.  w05 96.
+             w62 96.  w76 96.  w96 96. ;
+
+param pt (tr) :
+
+       18REG     24REG     24PRO    :=
+
+w01    1.194     1.429     1.429
+w05    1.194     1.509     1.509
+w96    0.000     1.600     1.600    ;
+
+param rpc (tr) :
+
+       18REG     24REG     24PRO    :=
+
+w01    2119.       2653.    2617.
+w05    2489.       3182.    3176.
+w96       0.       2925.    2918.   ;
+
+param opc (tr) :
+
+       18REG     24REG     24PRO    :=
+
+w01    2903.     3585.     3579.
+w05       0.        0.        0.
+w96       0.     3629.     3622.    ;
+
+param sc  default 99.99 (tr) :
+
+         w01     w02     w03     w04     w05     w62     w76     w96  :=
+
+w01      .      2.97    1.14    2.08    2.37    1.26    2.42    1.43
+w02     4.74     .      4.17    6.12    7.41    3.78    7.04    5.21
+w03     2.45    4.74     .      3.67    2.84    0.90    2.41    2.55
+w04     1.74    5.03    2.43     .      3.19    2.45    2.69    0.58
+w05     2.70    5.16    2.84    2.85     .      3.26    3.34    2.71
+w06     1.99    4.17    2.13    2.19    2.52    2.06    2.00    1.51
+w08     0.21    2.92    1.24    2.07    2.29    1.25    2.32    1.55
+w09     0.66    3.76    1.41    2.47    1.82    1.66     .      1.87
+w12     1.38    3.83    1.68    2.53    2.39     .      1.96    1.94
+w14     2.47    1.58    2.40    3.59    3.85    2.25     .      3.05
+w15     1.06    4.95    2.48    1.39    3.41    1.96     .      1.02
+w17     0.88    3.39    1.46    2.00    2.67    1.45     .      1.46
+w18     7.90    6.57    7.79    9.59    10.81    .       .      6.70
+w19     1.42    4.12    1.96    1.99    3.52    1.88     .      1.26
+w20     3.03    1.59    2.34    4.76    3.98    1.88     .      3.73
+w24     1.58    2.80    2.27    2.87    3.19    1.31     .      2.05
+w25     1.51    5.05    2.74    0.57    2.98     .      2.95    0.27
+w26     1.75    3.61    2.70    1.54    4.07    3.52     .      1.03
+w27     2.48    6.87    3.17    1.59    2.08    3.45     .      0.99
+w28     2.05    6.83    2.97    1.13    2.91     .       .      1.26
+w29     4.03    3.68    4.46    3.20    5.50     .       .      3.20
+w30     2.48    5.78    2.99    2.24    1.79    3.10     .      1.39
+w31     2.34    5.41    2.87    1.67    1.66     .       .      1.39
+w32     14.36    .       .       .       .       .       .       .
+w33     3.87    4.27    5.11    3.48    5.66    4.03     .      3.05
+w34     3.26    4.80    3.21    2.70    4.14     .       .      1.77
+w35     2.34    2.84    2.89    3.35    3.78    2.68     .      2.52
+w36     2.43    5.69    2.96    2.95    1.02    2.61    1.07    2.54
+w37     2.23    4.64    2.41    1.99    4.30    2.61     .      1.44
+w38     4.66    4.36    5.23    3.04    4.46     .       .      3.82
+w39     1.11    3.51    1.10    2.53    3.07    1.12     .      2.23
+w40     2.99    4.78    4.23    1.57    3.92     .       .      1.80
+w41     4.93    4.00    5.43    4.45    6.31     .       .      3.81
+w42     3.86    6.55    5.03    2.11    4.41     .       .      2.63
+w43     4.61    4.45    3.77    1.22    4.31     .       .      2.35
+w44     2.05    4.48    1.06    3.70    3.46    1.10     .      3.21
+w45     0.92    3.42    1.58    3.04    1.82    1.94     .      2.52
+w46     1.36    2.44    0.95    3.08    2.78    0.39    2.16    2.37
+w47     1.30    3.39    1.60    2.49    4.29    2.04     .      1.68
+w48     1.65    3.78    1.03    2.97    2.21    1.31     .      2.74
+w49     1.96    3.00    1.50    3.24    3.68    1.00     .      2.99
+w50     0.90    4.14    1.60    1.95    3.61    1.61     .      1.52
+w51     1.59    3.95    0.25    2.96    2.58    1.00    2.41    2.71
+w53     1.59    3.79    1.28    3.12    3.10    0.89     .      2.98
+w54     1.72    4.36    1.61    2.92    2.34    1.91    1.97    3.05
+w55     2.45    2.73    2.21    4.47    4.30    2.57     .      4.48
+w56     1.10    3.73    1.59    2.74    2.33    1.45     .      2.44
+w57     0.95    3.39    1.37    2.30    2.47    1.15     .      1.95
+w59     3.29    5.35    3.32    3.81    1.52    3.38    1.34    4.08
+w60     2.41    6.12    2.46    3.65    2.35     .      1.37    4.06
+w61     3.32    5.50    3.41    3.38    1.23     .      0.99    4.28
+w62     1.12    3.00    0.82    3.22    2.95     .      3.33    2.53
+w63     3.59    6.36    3.25    4.12    1.84    3.59    1.46    4.03
+w64     1.85    4.45    2.17    3.43    2.13    2.03     .      4.02
+w65     2.78    4.79    2.81    2.94    1.54    2.90    1.07    2.94
+w66     3.90    5.79    3.05    3.65    1.36    3.39    1.22    3.57
+w68     2.61    5.20    2.90    2.34    1.68    3.19    1.48    2.31
+w69     2.94    5.21    2.78    3.43    0.21    3.26    0.68    2.54
+w71     2.06    4.98    2.38    2.44    1.59    2.97    1.05    2.55
+w72     2.61    5.50    2.83    3.12    1.35    3.23    0.88    2.99
+w73     8.52    6.16    8.03    8.83    10.44   7.38    10.26    .
+w74     6.11    5.46    9.07    9.38    10.80    .       .      8.25
+w75     2.66    4.94    2.87    3.69    1.52    3.15    1.24    4.00
+w76     1.99    5.26    2.23    3.36    0.58    3.17     .      2.50
+w77     4.32    3.07    5.05    3.88    6.04     .       .      4.15
+w78     5.60    2.59    5.78    5.56    7.10     .       .      5.60
+w79     4.25    2.32    4.93    4.57    6.04     .       .      4.58
+w80     5.94    4.00    5.60    7.02    9.46     .       .      7.51
+w81     5.39    2.21    5.10    6.22    6.46     .       .      6.58
+w82     8.80    5.69    9.29    9.88    11.69   8.63    11.52    .
+w83     4.40     .      5.24    5.21    5.81    3.91    7.04    5.33
+w84     5.87    5.43    6.17    5.70    7.63     .       .      5.70
+w85     3.90    3.65    3.38    4.57    5.64    3.05     .      5.04
+w86     5.48    2.10    5.70    6.37    7.33     .       .      6.19
+w87     8.88    5.54    9.50    9.71    11.64   8.85    11.68    .
+w89     4.62    4.01    4.03    6.30    6.30    3.81     .      7.77
+w90     4.35    2.72    4.61    4.01    5.60     .       .      3.20
+w91     7.61    4.42    7.83    6.85    8.79     .       .      7.66
+w92     7.15    2.69    6.91    7.20     .       .       .      7.06
+w93     3.17    3.95    4.37    3.74    5.05     .       .      2.40
+w94     1.21    3.07    0.90    2.74    3.17     .      2.63    2.39
+w95     5.82    3.29    6.55    7.06    11.47    .       .      7.83
+w96     1.77    5.20    2.72    0.59    3.47    2.48     .       .
+w98     3.04    1.92    3.64    3.70    4.90    3.05     .      3.88
+x22     4.08    6.25    4.15    4.30    1.77     .      1.77     .
+x23     3.39    5.74    3.55    4.08    1.69     .      1.47     .      ;
+
+param msr (tr) :
+
+         w01     w02     w03     w04     w05     w62     w76     w96    :=
+
+w01        0       0       0       0       0       0       1       0
+w02        0       0       0       0       0       0       1       0
+w03        0       0       0       0       0       0       1       0
+w04        0       0       0       0       0       0       1       0
+w05        0       0       0       0       0       0       0       0
+w06        0       1       1       1       1       1       1       1
+w08        0       1       1       1       1       1       1       1
+w09        0       1       1       1       1       1       0       1
+w12        0       1       1       1       1       0       1       1
+w14        1       1       1       1       1       0       0       1
+w15        0       1       1       1       1       1       0       1
+w17        0       1       1       1       1       1       0       1
+w18        0       1       1       1       1       0       0       1
+w19        0       1       1       1       1       0       0       1
+w20        1       1       1       1       1       0       0       1
+w24        0       1       1       1       1       0       0       1
+w25        0       1       1       1       1       0       1       0
+w26        1       1       1       0       1       1       0       1
+w27        1       1       1       0       1       1       0       1
+w28        1       1       1       0       1       0       0       1
+w29        0       1       1       1       1       0       0       1
+w30        1       1       1       0       1       1       0       1
+w31        1       1       1       0       1       0       0       1
+w32        0       0       0       0       0       0       0       0
+w33        1       0       1       1       1       1       0       1
+w34        1       1       1       0       1       0       0       1
+w35        1       1       1       1       1       0       0       1
+w36        0       1       1       1       0       1       1       1
+w37        1       1       1       0       1       1       0       1
+w38        1       1       1       0       1       0       0       1
+w39        0       1       1       1       1       1       0       1
+w40        1       1       1       0       1       0       0       1
+w41        1       0       1       1       1       0       0       1
+w42        1       1       1       0       1       0       0       1
+w43        1       1       1       0       1       0       0       1
+w44        1       1       1       1       1       0       0       1
+w45        0       1       1       1       1       1       0       1
+w46        0       1       1       1       1       0       1       1
+w47        0       1       1       1       1       1       0       1
+w48        0       1       1       1       1       0       0       1
+w49        1       1       1       1       1       0       0       1
+w50        0       1       1       1       1       1       0       1
+w51        0       1       1       1       1       0       1       1
+w53        1       1       1       1       1       0       0       1
+w54        0       1       1       1       1       1       1       1
+w55        0       1       1       1       1       0       0       1
+w56        0       1       1       1       1       1       0       1
+w57        0       1       1       1       1       1       0       1
+w59        0       1       1       1       0       1       1       1
+w60        0       1       1       1       1       0       1       1
+w61        0       1       1       1       0       0       1       1
+w62        0       0       0       0       0       0       1       0
+w63        0       1       1       1       0       1       1       1
+w64        0       1       1       1       1       1       0       1
+w65        0       1       1       1       0       1       1       1
+w66        0       1       1       1       0       1       1       1
+w68        0       1       1       1       0       1       1       1
+w69        0       1       1       1       0       1       1       1
+w71        0       1       1       1       0       1       1       1
+w72        0       1       1       1       0       1       1       1
+w73        0       1       1       1       0       1       1       0
+w74        0       1       1       1       0       0       0       1
+w75        0       1       1       1       0       1       1       1
+w76        0       0       0       0       0       0       0       0
+w77        1       0       1       1       1       0       0       1
+w78        1       0       1       1       1       0       0       1
+w79        1       0       1       1       1       0       0       1
+w80        1       0       1       1       1       0       0       1
+w81        1       0       1       1       1       0       0       1
+w82        1       0       1       1       1       1       1       0
+w83        1       0       1       1       1       0       1       1
+w84        1       0       1       1       1       0       0       1
+w85        1       1       1       1       1       0       0       1
+w86        1       0       1       1       1       0       0       1
+w87        1       0       1       1       1       1       1       0
+w89        1       0       1       1       1       1       0       1
+w90        0       1       1       1       1       0       0       1
+w91        1       0       1       1       1       0       0       1
+w92        1       0       1       1       1       0       0       1
+w93        1       1       1       0       1       0       0       1
+w94        0       0       1       1       1       0       1       1
+w95        1       0       1       1       1       0       0       1
+w96        0       0       0       0       0       0       0       0
+w98        1       0       1       1       1       1       0       1
+x22        1       1       1       1       0       0       1       0
+x23        1       1       1       1       0       0       1       0    ;
+
+param ds default 0.000 (tr) :
+
+         18REG     24REG     24PRO    :=
+
+w01      0.000     0.000     0.008
+w02      0.004     0.000     0.000
+w03      0.000     0.000     0.000
+w04      0.010     0.002     0.000
+w05      0.000     0.000     0.000
+w06      0.010     0.008     0.008
+w08      0.030     0.024     0.024
+w09      0.014     0.018     0.020
+w12      0.014     0.012     0.010
+w14      0.007     0.007     0.012
+w15      0.010     0.019     0.018
+w17      0.013     0.010     0.011
+w19      0.015     0.012     0.009
+w20      0.012     0.021     0.022
+w21      0.000     0.000     0.000
+w24      0.012     0.022     0.018
+w25      0.019     0.025     0.020
+w26      0.006     0.015     0.021
+w27      0.008     0.010     0.015
+w28      0.011     0.016     0.019
+w29      0.008     0.020     0.013
+w30      0.011     0.013     0.015
+w31      0.011     0.013     0.017
+w32      0.006     0.000     0.000
+w33      0.000     0.015     0.014
+w34      0.008     0.007     0.005
+w35      0.002     0.006     0.014
+w36      0.015     0.013     0.005
+w37      0.017     0.016     0.015
+w38      0.015     0.009     0.012
+w39      0.007     0.017     0.022
+w40      0.009     0.014     0.020
+w41      0.003     0.014     0.011
+w42      0.017     0.011     0.012
+w43      0.009     0.013     0.011
+w44      0.002     0.012     0.012
+w45      0.016     0.025     0.028
+w46      0.038     0.062     0.040
+w47      0.007     0.010     0.010
+w48      0.003     0.015     0.016
+w49      0.005     0.016     0.017
+w50      0.011     0.008     0.007
+w51      0.010     0.022     0.021
+w53      0.004     0.026     0.020
+w54      0.020     0.017     0.025
+w55      0.004     0.019     0.028
+w56      0.004     0.010     0.008
+w57      0.014     0.020     0.018
+w59      0.012     0.006     0.007
+w60      0.019     0.010     0.009
+w61      0.028     0.010     0.012
+w62      0.000     0.000     0.000
+w63      0.070     0.027     0.037
+w64      0.009     0.004     0.005
+w65      0.022     0.015     0.016
+w66      0.046     0.017     0.020
+w68      0.005     0.012     0.016
+w69      0.085     0.036     0.039
+w71      0.011     0.013     0.010
+w72      0.089     0.031     0.034
+w75      0.026     0.012     0.010
+w77      0.001     0.004     0.002
+w78      0.002     0.004     0.002
+w79      0.001     0.004     0.002
+w80      0.001     0.001     0.002
+w81      0.001     0.003     0.002
+w83      0.009     0.010     0.008
+w84      0.001     0.002     0.002
+w85      0.001     0.004     0.005
+w86      0.001     0.002     0.002
+w87      0.002     0.003     0.000
+w89      0.001     0.001     0.002
+w90      0.006     0.017     0.013
+w91      0.002     0.010     0.013
+w92      0.000     0.003     0.002
+w93      0.002     0.006     0.007
+w95      0.001     0.007     0.007
+w96      0.000     0.000     0.000
+w98      0.006     0.005     0.002    ;
+
+end;
Index: deps/glpk/examples/egypt.mod
===================================================================
--- deps/glpk/examples/egypt.mod	(revision 9)
+++ deps/glpk/examples/egypt.mod	(revision 9)
@@ -0,0 +1,519 @@
+# EGYPT, a static model of fertilizer production
+#
+# References:
+# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
+# for Mathematical Programming." Management Science 36 (1990) 519-554.
+
+###  SETS  ###
+
+set center;                # Locations from which final product may be shipped
+set port within center;    # Locations at which imports can be received
+set plant within center;   # Locations of plants
+
+set region;                # Demand regions
+
+set unit;                  # Productive units
+set proc;                  # Processes
+
+set nutr;                  # Nutrients
+
+set c_final;               # Final products (fertilizers)
+set c_inter;               # Intermediate products
+set c_ship within c_inter; # Intermediates for shipment
+set c_raw;                 # Domestic raw materials and miscellaneous inputs
+
+set commod := c_final union c_inter union c_raw;
+
+                           # All commodities
+
+###  PARAMETERS  ###
+
+param cf75 {region,c_final} >= 0;
+
+                           # Consumption of fertilizer 1974-75 (1000 tpy)
+
+param fn {c_final,nutr} >= 0;
+
+                           # Nutrient content of fertilizers
+
+param cn75 {r in region, n in nutr} := sum {c in c_final} cf75[r,c] * fn[c,n];
+
+                           # Consumption of nutrients 1974-75 (1000 tpy)
+
+param road {region,center} >= 0;
+
+                           # Road distances
+
+param rail_half {plant,plant} >= 0;
+param rail {p1 in plant, p2 in plant} :=
+    if rail_half[p1,p2] > 0 then rail_half[p1,p2] else rail_half[p2,p1];
+
+                           # Interplant rail distances (kms)
+
+param impd_barg {plant} >= 0;
+param impd_road {plant} >= 0;
+
+                           # Import distances (kms) by barge and road
+
+param tran_final {pl in plant, r in region} :=
+              if road[r,pl] > 0 then .5 + .0144 * road[r,pl] else 0;
+
+param tran_import {r in region, po in port} :=
+              if road[r,po] > 0 then .5 + .0144 * road[r,po] else 0;
+
+param tran_inter {p1 in plant, p2 in plant} :=
+              if rail[p1,p2] > 0 then 3.5 + .03 * rail[p1,p2] else 0;
+
+param tran_raw {pl in plant} :=
+            (if impd_barg[pl] > 0 then 1.0 + .0030 * impd_barg[pl] else 0)
+          + (if impd_road[pl] > 0 then 0.5 + .0144 * impd_road[pl] else 0);
+
+                           # Transport cost (le per ton) for:
+                           #   final products, imported final products,
+                           #   interplant shipment, imported raw materials
+
+param io {commod,proc};    # Input-output coefficients
+
+param util {unit,proc} >= 0;
+
+                           # Capacity utilization coefficients
+
+param p_imp {commod} >= 0; # Import Price (cif US$ per ton 1975)
+
+param p_r {c_raw} >= 0;
+param p_pr {plant,c_raw} >= 0;
+
+param p_dom {pl in plant, c in c_raw} :=
+              if p_r[c] > 0 then p_r[c] else p_pr[pl,c];
+
+                           # Domestic raw material prices
+
+param dcap {plant,unit} >= 0;
+
+                           # Design capacity of plants (t/day)
+
+param icap {u in unit, pl in plant} := 0.33 * dcap[pl,u];
+
+                           # Initial capacity of plants (t/day)
+
+param exch := 0.4;         # Exchange rate
+
+param util_pct := 0.85;    # Utilization percent for initial capacity
+
+###  DERIVED SETS OF "POSSIBILITIES"  ###
+
+set m_pos {pl in plant} := {u in unit: icap[u,pl] > 0};
+
+                           # At each plant, set of units for which there is
+                           # initial capacity
+
+set p_cap {pl in plant} :=
+             {pr in proc: forall {u in unit: util[u,pr] > 0} u in m_pos[pl] };
+
+                           # At each plant, set of processes for which
+                           # all necessary units have some initial capacity
+
+set p_except {plant} within proc;
+
+                           # At each plant, list of processes that are
+                           # arbitrarily ruled out
+
+set p_pos {pl in plant} := p_cap[pl] diff p_except[pl];
+
+                           # At each plant, set of possible processes
+
+set cp_pos {c in commod} := {pl in plant: sum {pr in p_pos[pl]} io[c,pr] > 0};
+
+set cc_pos {c in commod} := {pl in plant: sum {pr in p_pos[pl]} io[c,pr] < 0};
+
+set c_pos {c in commod} := cp_pos[c] union cc_pos[c];
+
+                           # For each commodity, set of plants that can
+                           # produce it (cp_pos) or consume it (cc_pos),
+                           # and their union (c_pos)
+
+###  VARIABLES  ###
+
+var Z {pl in plant, p_pos[pl]} >= 0;
+
+                           # Z[pl,pr] is level of process pr at plant pl
+
+var Xf {c in c_final, cp_pos[c], region} >= 0;
+
+                           # Xf[c,pl,r] is amount of final product c
+                           # shipped from plant pl to region r
+
+var Xi {c in c_ship, cp_pos[c], cc_pos[c]} >= 0;
+
+                           # Xi[c,p1,p2] is amount of intermediate c
+                           # shipped from plant p1 to plant p2
+
+var Vf {c_final,region,port} >= 0;
+
+                           # Vf[c,r,po] is amount of final product c
+                           # imported by region r from port po
+
+var Vr {c in c_raw, cc_pos[c]} >= 0;
+
+                           # Vr[c,pl] is amount of raw material c
+                           # imported for use at plant pl
+
+var U {c in c_raw, cc_pos[c]} >= 0;
+
+                           # U[c,pl] is amount of raw material c
+                           # purchased domestically for use at plant pl
+
+var Psip;                  # Domestic recurrent cost
+var Psil;                  # Transport cost
+var Psii;                  # Import cost
+
+###  OBJECTIVE  ###
+
+minimize Psi:  Psip + Psil + Psii;
+
+###  CONSTRAINTS  ###
+
+subject to mbd {n in nutr, r in region}:
+
+    sum {c in c_final} fn[c,n] *
+                (sum {po in port} Vf[c,r,po] +
+                 sum {pl in cp_pos[c]} Xf[c,pl,r])  >=  cn75[r,n];
+
+                           # Total nutrients supplied to a region by all
+                           # final products (sum of imports plus internal
+                           # shipments from plants) must meet requirements
+
+subject to mbdb {c in c_final, r in region: cf75[r,c] > 0}:
+
+    sum {po in port} Vf[c,r,po] +
+    sum {pl in cp_pos[c]} Xf[c,pl,r]  >=  cf75[r,c];
+
+                           # Total of each final product supplied to each
+                           # region (as in previous constraint) must meet
+                           # requirements
+
+subject to mb {c in commod, pl in plant}:
+
+    sum {pr in p_pos[pl]} io[c,pr] * Z[pl,pr]
+
+   + ( if c in c_ship then
+                ( if pl in cp_pos[c] then sum {p2 in cc_pos[c]} Xi[c,pl,p2] )
+              - ( if pl in cc_pos[c] then sum {p2 in cp_pos[c]} Xi[c,p2,pl] ))
+
+   + ( if (c in c_raw and pl in cc_pos[c]) then
+                 (( if p_imp[c] > 0 then Vr[c,pl] )
+                + ( if p_dom[pl,c] > 0 then U[c,pl] )))
+
+  >= if (c in c_final and pl in cp_pos[c]) then sum {r in region} Xf[c,pl,r];
+
+                           # For each commodity at each plant:  sum of
+                           #   (1) production or consumption at plant,
+                           #   (2) inter-plant shipments in or out,
+                           #   (3) import and domestic purchases (raw only)
+                           # is >= 0 for raw materials and intermediates;
+                           # is >= the total shipped for final products
+
+subject to cc {pl in plant, u in m_pos[pl]}:
+
+    sum {pr in p_pos[pl]} util[u,pr] * Z[pl,pr]  <=  util_pct * icap[u,pl];
+
+                           # For each productive unit at each plant,
+                           # total utilization by all processes
+                           # may not exceed the unit's capacity
+
+subject to ap:
+
+    Psip  =  sum {c in c_raw, pl in cc_pos[c]} p_dom[pl,c] * U[c,pl];
+
+                           # Psip is the cost of domestic raw materials,
+                           # summed over all plants that consume them
+
+subject to al:
+
+    Psil  =  sum {c in c_final} (
+
+               sum {pl in cp_pos[c], r in region}
+                                              tran_final[pl,r] * Xf[c,pl,r]
+
+             + sum {po in port, r in region} tran_import[r,po] * Vf[c,r,po] )
+
+           + sum {c in c_ship, p1 in cp_pos[c], p2 in cc_pos[c]}
+                                               tran_inter[p1,p2] * Xi[c,p1,p2]
+
+           + sum {c in c_raw, pl in cc_pos[c]: p_imp[c] > 0}
+                                                    tran_raw[pl] * Vr[c,pl];
+
+                           # Total transport cost is sum of shipping costs for
+                           #   (1) all final products from all plants,
+                           #   (2) all imports of final products,
+                           #   (3) all intermediates shipped between plants,
+                           #   (4) all imports of raw materials
+
+subject to ai:
+
+    Psii / exch  =  sum {c in c_final, r in region, po in port}
+                                                      p_imp[c] * Vf[c,r,po]
+
+                  + sum {c in c_raw, pl in cc_pos[c]} p_imp[c] * Vr[c,pl];
+
+                           # Total import cost -- at exchange rate --
+                           # is sum of import costs for final products
+                           # in each region and raw materials at each plant
+
+###  DATA  ###
+
+data;
+
+set center := ASWAN HELWAN ASSIOUT KAFR_EL_ZT ABU_ZAABAL ABU_KIR TALKHA SUEZ ;
+
+set port := ABU_KIR ;
+
+set plant := ASWAN HELWAN ASSIOUT KAFR_EL_ZT ABU_ZAABAL ;
+
+set region := ALEXANDRIA BEHERA GHARBIA KAFR_EL_SH DAKAHLIA DAMIETTA
+              SHARKIA ISMAILIA SUEZ MENOUFIA KALUBIA GIZA BENI_SUEF FAYOUM
+              MINIA ASSIOUT NEW_VALLEY SOHAG QUENA ASWAN ;
+
+set unit := SULF_A_S SULF_A_P NITR_ACID AMM_ELEC AMM_C_GAS C_AMM_NITR
+            AMM_SULF SSP ;
+
+set proc := SULF_A_S SULF_A_P NITR_ACID AMM_ELEC AMM_C_GAS CAN_310 CAN_335
+            AMM_SULF SSP_155 ;
+
+set nutr := N P205 ;
+
+set c_final := UREA CAN_260 CAN_310 CAN_335 AMM_SULF DAP SSP_155 C_250_55
+               C_300_100 ;
+
+set c_inter := AMMONIA NITR_ACID SULF_ACID ;
+
+set c_ship := AMMONIA SULF_ACID ;
+
+set c_raw := EL_ASWAN COKE_GAS PHOS_ROCK LIMESTONE EL_SULFUR PYRITES
+             ELECTRIC BF_GAS WATER STEAM BAGS ;
+
+set p_except[ASWAN] := CAN_335 ;
+set p_except[HELWAN] := CAN_310 ;
+set p_except[ASSIOUT] := ;
+set p_except[KAFR_EL_ZT] := ;
+set p_except[ABU_ZAABAL] := ;
+
+param cf75  default 0.0  :
+
+               CAN_260    CAN_310    CAN_335    AMM_SULF     UREA   :=
+
+ALEXANDRIA        .           .         5.0        3.0        1.0
+ASSIOUT          1.0        20.0       26.0        1.0       27.0
+ASWAN             .         40.0         .          .          .
+BEHERA           1.0          .        25.0       90.0       35.0
+BENI_SUEF        1.0          .        15.0        1.0       20.0
+DAKAHLIA         1.0          .        26.0       60.0       20.0
+DAMIETTA          .           .         2.0       15.0        8.0
+FAYOUM           1.0          .        20.0        6.0       20.0
+GHARBIA           .           .        17.0       60.0       28.0
+GIZA              .           .        40.0        6.0        2.0
+ISMAILIA          .           .         4.0        6.0        2.0
+KAFR_EL_SH       1.0          .        10.0       45.0       22.0
+KALUBIA           .           .        25.0       16.0        7.0
+MENOUFIA         1.0          .        24.0       21.0       30.0
+MINIA            2.0        15.0       35.0        1.0       41.0
+NEW_VALLEY        .           .          .          .         1.0
+QUENA             .         95.0        2.0         .         3.0
+SHARKIA          1.0          .        31.0       50.0       28.0
+SOHAG             .         65.0        3.0         .         7.0
+SUEZ              .           .         1.0         .          .
+
+   :          SSP_155    C_250_55   C_300_100    DAP   :=
+
+ALEXANDRIA       8.0         .          .         .
+ASSIOUT         35.0        5.0         .1        .
+ASWAN            8.0         .          .         .
+BEHERA          64.0        1.0         .1        .1
+BENI_SUEF       13.0        3.0         .         .
+DAKAHLIA        52.0        1.0         .         .
+DAMIETTA         5.0         .          .         .
+FAYOUM          17.0        1.0         .         .
+GHARBIA         57.0        1.0         .2        .1
+GIZA            14.0        1.0         .1        .
+ISMAILIA         4.0         .          .         .
+KAFR_EL_SH      25.0        2.0         .1        .
+KALUBIA         22.0        1.0         .         .1
+MENOUFIA        33.0        2.0         .1        .1
+MINIA           50.0        3.0         .2        .1
+NEW_VALLEY       1.0         .          .         .
+QUENA            8.0         .          .         .
+SHARKIA         43.0        1.0         .1        .
+SOHAG           20.0        1.0         .         .
+SUEZ             1.0         .          .         .        ;
+
+param fn  default 0.0 :      N     P205    :=
+
+            AMM_SULF       .206     .
+            CAN_260        .26      .
+            CAN_310        .31      .
+            CAN_335        .335     .
+            C_250_55       .25      .055
+            C_300_100      .30      .10
+            DAP            .18      .46
+            SSP_155        .        .15
+            UREA           .46      .      ;
+
+param road  default 0.0  :
+
+            ABU_KIR ABU_ZAABAL ASSIOUT ASWAN HELWAN KAFR_EL_ZT SUEZ TALKHA :=
+
+ALEXANDRIA      16     210       607    1135   244      119     362   187
+ASSIOUT        616     420         .     518   362      504     527   518
+ASWAN         1134     938       518       .   880     1022    1045  1036
+BEHERA          76      50       547    1065   184       42     288   120
+BENI_SUEF      359     163       257     775   105      248     270   261
+DAKAHLIA       208     138       515    1033   152       58     219     3
+DAMIETTA       267     216       596    1114   233      131     286    66
+FAYOUM         341     145       308     826    88      230     252   243
+GHARBIA        150      65       485    1003   122       20     226    55
+GIZA           287      48       372     890    .9      133     169   146
+ISMAILIA       365     142       536    1054   173      241      89   146
+KAFR_EL_SH     145     105       525    1043   162       20     266    35
+KALUBIA        190      97       439     957    76       66     180    81
+MENOUFIA       157     154       472     990   109       33     213    90
+MINIA          384     288       132     650   230      372     394   386
+NEW_VALLEY     815     619       199     519   561      703     726   717
+QUENA          858     662       242     276   604      746     769   760
+SHARKIA        240      60       473     991   110       78     214    58
+SOHAG          715     519        99     419   461      603     626   617
+SUEZ           370     224       541    1059   178      246       .   298  ;
+
+param rail_half  default 0  :
+
+              KAFR_EL_ZT   ABU_ZAABAL    HELWAN     ASSIOUT   :=
+
+ABU_ZAABAL         85            .           .          .
+HELWAN            142           57           .          .
+ASSIOUT           504          420         362          .
+ASWAN            1022          938         880        518     ;
+
+param :            impd_barg   impd_road :=
+
+ABU_ZAABAL            210          .1
+ASSIOUT               583         0
+ASWAN                1087        10
+HELWAN                183         0
+KAFR_EL_ZT            104         6 ;
+
+param io  default 0.0  :=
+
+   [*,AMM_C_GAS]  AMMONIA        1.0
+                  BF_GAS      -609.
+                  COKE_GAS      -2.0
+                  ELECTRIC   -1960.
+                  STEAM         -4.
+                  WATER       -700.
+
+   [*,AMM_ELEC]   AMMONIA        1.0
+                  EL_ASWAN     -12.0
+
+   [*,AMM_SULF]   AMMONIA        -.26
+                  AMM_SULF       1.0
+                  BAGS         -22.
+                  ELECTRIC     -19.
+                  SULF_ACID      -.76
+                  WATER        -17.
+
+   [*,CAN_310]    AMMONIA        -.20
+                  BAGS         -23.
+                  CAN_310        1.0
+                  LIMESTONE      -.12
+                  NITR_ACID      -.71
+                  STEAM          -.4
+                  WATER        -49.
+
+   [*,CAN_335]    AMMONIA        -.21
+                  BAGS         -23.
+                  CAN_335        1.0
+                  LIMESTONE      -.04
+                  NITR_ACID      -.76
+                  STEAM          -.4
+                  WATER        -49.
+
+   [*,NITR_ACID]  AMMONIA        -.292
+                  ELECTRIC    -231.
+                  NITR_ACID      1.0
+                  WATER          -.6
+
+   [*,SSP_155]    BAGS         -22.
+                  ELECTRIC     -14.
+                  PHOS_ROCK      -.62
+                  SSP_155        1.0
+                  SULF_ACID      -.41
+                  WATER         -6.
+
+   [*,SULF_A_P]   ELECTRIC     -75.
+                  PYRITES        -.826
+                  SULF_ACID      1.0
+                  WATER        -60.
+
+   [*,SULF_A_S]   ELECTRIC     -50.
+                  EL_SULFUR      -.334
+                  SULF_ACID      1.0
+                  WATER        -20. ;
+
+param util  default 0  :=
+
+   [*,*]   SULF_A_S SULF_A_S    1      SULF_A_P SULF_A_P   1
+           NITR_ACID NITR_ACID  1      AMM_ELEC AMM_ELEC   1
+           AMM_C_GAS AMM_C_GAS  1      SSP SSP_155         1
+           C_AMM_NITR CAN_310   1      C_AMM_NITR CAN_335  1
+           AMM_SULF AMM_SULF    1 ;
+
+param p_imp  default 0.0  :=
+
+     PYRITES       17.5           AMM_SULF      75.
+     EL_SULFUR     55.            DAP          175.
+     UREA         150.            SSP_155       80.
+     CAN_260       75.            C_250_55     100.
+     CAN_310       90.            C_300_100    130.
+     CAN_335      100.   ;
+
+param p_r  default 0.0  :=
+
+     ELECTRIC     .007
+     BF_GAS       .007
+     WATER        .031
+     STEAM       1.25
+     BAGS         .28   ;
+
+param p_pr  default 0.0  :=
+
+ [HELWAN,COKE_GAS]              16.0
+ [ASWAN,EL_ASWAN]                1.0
+
+ [*,LIMESTONE]      ASWAN        1.2
+                    HELWAN       1.2
+
+ [*,PHOS_ROCK]      ABU_ZAABAL   4.0
+                    ASSIOUT      3.5
+                    KAFR_EL_ZT   5.0   ;
+
+param dcap  default 0.0  :=
+
+   [ABU_ZAABAL,*]   SSP          600
+                    SULF_A_P     227
+                    SULF_A_S     242
+
+   [ASSIOUT,*]      SSP          600
+                    SULF_A_S     250
+
+   [ASWAN,*]        AMM_ELEC     450
+                    C_AMM_NITR  1100
+                    NITR_ACID    800
+
+   [HELWAN,*]       AMM_C_GAS    172
+                    AMM_SULF      24
+                    C_AMM_NITR   364
+                    NITR_ACID    282
+
+   [KAFR_EL_ZT,*]   SSP          600
+                    SULF_A_P      50
+                    SULF_A_S     200  ;
+
+end;
Index: deps/glpk/examples/fctp.mod
===================================================================
--- deps/glpk/examples/fctp.mod	(revision 9)
+++ deps/glpk/examples/fctp.mod	(revision 9)
@@ -0,0 +1,93 @@
+/* FCTP, Fixed-Charge Transportation Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Fixed-Charge Transportation Problem (FCTP) is obtained from
+   classical transportation problem by imposing a fixed cost on each
+   transportation link if there is a positive flow on that link. */
+
+param m, integer, > 0;
+/* number of sources */
+
+param n, integer, > 0;
+/* number of customers */
+
+set I := 1..m;
+/* set of sources */
+
+set J := 1..n;
+/* set of customers */
+
+param supply{i in I}, >= 0;
+/* supply at source i */
+
+param demand{j in J}, >= 0;
+/* demand at customer j */
+
+param varcost{i in I, j in J}, >= 0;
+/* variable cost (a cost per one unit shipped from i to j) */
+
+param fixcost{i in I, j in J}, >= 0;
+/* fixed cost (a cost for shipping any amount from i to j) */
+
+var x{i in I, j in J}, >= 0;
+/* amount shipped from source i to customer j */
+
+s.t. f{i in I}: sum{j in J} x[i,j] = supply[i];
+/* observe supply at source i */
+
+s.t. g{j in J}: sum{i in I} x[i,j] = demand[j];
+/* satisfy demand at customer j */
+
+var y{i in I, j in J}, binary;
+/* y[i,j] = 1 means some amount is shipped from i to j */
+
+s.t. h{i in I, j in J}: x[i,j] <= min(supply[i], demand[j]) * y[i,j];
+/* if y[i,j] is 0, force x[i,j] to be 0 (may note that supply[i] and
+   demand[j] are implicit upper bounds for x[i,j] as follows from the
+   constraints f[i] and g[j]) */
+
+minimize cost: sum{i in I, j in J} varcost[i,j] * x[i,j] +
+               sum{i in I, j in J} fixcost[i,j] * y[i,j];
+/* total transportation costs */
+
+data;
+
+/* These data correspond to the instance bal8x12 from [Balinski]. */
+
+/* The optimal solution is 471.55 */
+
+param m := 8;
+
+param n := 12;
+
+param supply := 1 15.00,  2 20.00,  3 45.00,  4 35.00,
+                5 25.00,  6 35.00,  7 10.00,  8 25.00;
+
+param demand := 1 20.00,  2 15.00,  3 20.00,  4 15.00,
+                5  5.00,  6 20.00,  7 30.00,  8 10.00,
+                9 35.00, 10 25.00, 11 10.00, 12  5.00;
+
+param varcost
+      :   1    2    3    4    5    6    7    8    9    10   11   12  :=
+      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
+      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
+      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
+      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
+      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
+      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
+      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
+      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 ;
+
+param fixcost
+      :   1    2    3    4    5    6    7    8    9    10   11   12  :=
+      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
+      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
+      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
+      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
+      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
+      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
+      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
+      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 ;
+
+end;
Index: deps/glpk/examples/food.mod
===================================================================
--- deps/glpk/examples/food.mod	(revision 9)
+++ deps/glpk/examples/food.mod	(revision 9)
@@ -0,0 +1,127 @@
+/* Food Manufacture 1, section 12.1 in
+ * Williams, "Model Building in Mathematical Programming"
+ *
+ * Sebastian Nowozin <nowozin@gmail.com>
+ */
+
+set oils;
+set month;
+
+/* Buying prices of the raw oils in the next six month. */
+param buyingprices{month,oils};
+
+/* Actual amount bought in each month. */
+var buys{month,oils} >= 0;
+
+/* Stock for each oil. */
+var stock{month,oils} >= 0;
+
+/* Price of the produced product */
+param productprice >= 0;
+param storagecost;
+
+param oilhardness{oils} >= 0;
+
+/* Actual amount of output oil produced in each month */
+var production{m in month} >= 0;
+var useoil{m in month, o in oils} >= 0;
+
+maximize totalprofit:
+    sum{m in month} productprice*production[m]
+    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
+    - sum{m in month, o in oils} storagecost*stock[m,o];
+
+/* Constraints */
+
+/* 1. Starting stock */
+s.t. startstock{o in oils}:
+    stock[1,o] = 500;
+s.t. endstock{o in oils}:
+    stock[6,o] + buys[6,o] - useoil[6,o] >= 500;
+
+/* 2. Stock constraints */
+s.t. stocklimit{m in month, o in oils}:
+    stock[m,o] <= 1000;
+
+s.t. production1{m in month, o in oils}:
+    useoil[m,o] <= stock[m,o] + buys[m,o];
+s.t. production2{m1 in month, m2 in month, o in oils : m2 = m1+1}:
+    stock[m2,o] = stock[m1,o] + buys[m1,o] - useoil[m1,o];
+
+s.t. production3a{m in month}:
+    sum{o in oils} oilhardness[o]*useoil[m,o] >= 3*production[m];
+s.t. production3b{m in month}:
+    sum{o in oils} oilhardness[o]*useoil[m,o] <= 6*production[m];
+
+s.t. production4{m in month}:
+    production[m] = sum{o in oils} useoil[m,o];
+
+/* 3. Refining constraints */
+s.t. refine1{m in month}:
+    useoil[m,"VEG1"]+useoil[m,"VEG2"] <= 200;
+s.t. refine2{m in month}:
+    useoil[m,"OIL1"]+useoil[m,"OIL2"]+useoil[m,"OIL3"] <= 250;
+
+solve;
+
+for {m in month} {
+    printf "Month %d\n", m;
+    printf "PRODUCE %4.2f tons, hardness %4.2f\n", production[m],
+        (sum{o in oils} oilhardness[o]*useoil[m,o]) / (sum{o in oils} useoil[m,o]);
+
+    printf "\tVEG1\tVEG2\tOIL1\tOIL2\tOIL3\n";
+    printf "STOCK";
+    printf "%d", m;
+    for {o in oils} {
+        printf "\t%4.2f", stock[m,o];
+    }
+    printf "\nBUY";
+    for {o in oils} {
+        printf "\t%4.2f", buys[m,o];
+    }
+    printf "\nUSE";
+    printf "%d", m;
+    for {o in oils} {
+        printf "\t%4.2f", useoil[m,o];
+    }
+    printf "\n";
+    printf "\n";
+}
+printf "Total profit: %4.2f\n",
+    (sum{m in month} productprice*production[m]
+    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
+    - sum{m in month, o in oils} storagecost*stock[m,o]);
+printf "      turnover: %4.2f\n",
+    sum{m in month} productprice*production[m];
+printf "      buying costs: %4.2f\n",
+    sum{m in month, o in oils} buyingprices[m,o]*buys[m,o];
+printf "      storage costs: %4.2f\n",
+    sum{m in month, o in oils} storagecost*stock[m,o];
+
+
+data;
+
+param : oils : oilhardness :=
+    VEG1    8.8
+    VEG2    6.1
+    OIL1    2.0
+    OIL2    4.2
+    OIL3    5.0 ;
+
+set month := 1 2 3 4 5 6;
+
+param buyingprices
+
+:           VEG1    VEG2    OIL1    OIL2    OIL3    :=
+
+1           110     120     130     110     115
+2           130     130     110     90      115
+3           110     140     130     100     95
+4           120     110     120     120     125
+5           100     120     150     110     105
+6           90      100     140     80      135 ;
+
+param productprice := 150;
+param storagecost := 5;
+
+end;
Index: deps/glpk/examples/food2.mod
===================================================================
--- deps/glpk/examples/food2.mod	(revision 9)
+++ deps/glpk/examples/food2.mod	(revision 9)
@@ -0,0 +1,150 @@
+/* Food Manufacture 2, section 12.2 in
+ * Williams, "Model Building in Mathematical Programming"
+ *
+ * Sebastian Nowozin <nowozin@gmail.com>
+ */
+
+set oils;
+set month;
+
+/* Buying prices of the raw oils in the next six month. */
+param buyingprices{month,oils};
+
+/* Actual amount bought in each month. */
+var buys{month,oils} >= 0;
+
+/* Stock for each oil. */
+var stock{month,oils} >= 0;
+
+/* Price of the produced product */
+param productprice >= 0;
+param storagecost;
+
+param oilhardness{oils} >= 0;
+param M >= 0;
+
+/* Actual amount of output oil produced in each month */
+var production{m in month} >= 0;
+var useoil{m in month, o in oils} >= 0, <= M;
+var useoilb{m in month, o in oils}, binary;
+
+maximize totalprofit:
+    sum{m in month} productprice*production[m]
+    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
+    - sum{m in month, o in oils} storagecost*stock[m,o];
+
+/* Constraints */
+
+/* 1. Starting stock */
+s.t. startstock{o in oils}:
+    stock[1,o] = 500;
+s.t. endstock{o in oils}:
+    stock[6,o] + buys[6,o] - useoil[6,o] >= 500;
+
+/* 2. Stock constraints */
+s.t. stocklimit{m in month, o in oils}:
+    stock[m,o] <= 1000;
+
+s.t. production1{m in month, o in oils}:
+    useoil[m,o] <= stock[m,o] + buys[m,o];
+s.t. production2{m1 in month, m2 in month, o in oils : m2 = m1+1}:
+    stock[m2,o] = stock[m1,o] + buys[m1,o] - useoil[m1,o];
+
+s.t. production3a{m in month}:
+    sum{o in oils} oilhardness[o]*useoil[m,o] >= 3*production[m];
+s.t. production3b{m in month}:
+    sum{o in oils} oilhardness[o]*useoil[m,o] <= 6*production[m];
+
+s.t. production4{m in month}:
+    production[m] = sum{o in oils} useoil[m,o];
+
+/* 3. Refining constraints */
+s.t. refine1{m in month}:
+    useoil[m,"VEG1"]+useoil[m,"VEG2"] <= 200;
+s.t. refine2{m in month}:
+    useoil[m,"OIL1"]+useoil[m,"OIL2"]+useoil[m,"OIL3"] <= 250;
+
+/* 4. Additional conditions:
+ *    i) The food may never be made up of more than three oils every month
+ */
+s.t. useoilb_calc{m in month, o in oils}:
+    M*useoilb[m,o] >= useoil[m,o];
+s.t. useoilb_limit{m in month}:
+    sum{o in oils} useoilb[m,o] <= 3;
+
+/* ii) If an oil is used in a month, at least 20 tons must be used.
+ */
+s.t. useminimum{m in month, o in oils}:
+    20*useoilb[m,o] <= useoil[m,o];
+
+/* iii) If either of VEG1 or VEG2 is used in a month, OIL2 must also be used
+ */
+s.t. use_oil2a{m in month}:
+    useoilb[m,"VEG1"] <= useoilb[m,"OIL3"];
+s.t. use_oil2b{m in month}:
+    useoilb[m,"VEG2"] <= useoilb[m,"OIL3"];
+
+solve;
+
+for {m in month} {
+    printf "Month %d\n", m;
+    printf "PRODUCE %4.2f tons, hardness %4.2f\n", production[m],
+        (sum{o in oils} oilhardness[o]*useoil[m,o]) / (sum{o in oils} useoil[m,o]);
+
+    printf "\tVEG1\tVEG2\tOIL1\tOIL2\tOIL3\n";
+    printf "STOCK";
+    printf "%d", m;
+    for {o in oils} {
+        printf "\t%4.2f", stock[m,o];
+    }
+    printf "\nBUY";
+    for {o in oils} {
+        printf "\t%4.2f", buys[m,o];
+    }
+    printf "\nUSE";
+    printf "%d", m;
+    for {o in oils} {
+        printf "\t%4.2f", useoil[m,o];
+    }
+    printf "\n";
+    printf "\n";
+}
+printf "Total profit: %4.2f\n",
+    (sum{m in month} productprice*production[m]
+    - sum{m in month, o in oils} buyingprices[m,o]*buys[m,o]
+    - sum{m in month, o in oils} storagecost*stock[m,o]);
+printf "      turnover: %4.2f\n",
+    sum{m in month} productprice*production[m];
+printf "      buying costs: %4.2f\n",
+    sum{m in month, o in oils} buyingprices[m,o]*buys[m,o];
+printf "      storage costs: %4.2f\n",
+    sum{m in month, o in oils} storagecost*stock[m,o];
+
+
+data;
+
+param : oils : oilhardness :=
+    VEG1    8.8
+    VEG2    6.1
+    OIL1    2.0
+    OIL2    4.2
+    OIL3    5.0 ;
+
+set month := 1 2 3 4 5 6;
+
+param buyingprices
+
+:           VEG1    VEG2    OIL1    OIL2    OIL3    :=
+
+1           110     120     130     110     115
+2           130     130     110     90      115
+3           110     140     130     100     95
+4           120     110     120     120     125
+5           100     120     150     110     105
+6           90      100     140     80      135 ;
+
+param productprice := 150;
+param storagecost := 5;
+param M := 1000;
+
+end;
Index: deps/glpk/examples/gap.mod
===================================================================
--- deps/glpk/examples/gap.mod	(revision 9)
+++ deps/glpk/examples/gap.mod	(revision 9)
@@ -0,0 +1,79 @@
+/* GAP, Generalized Assignment Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Generalized Assignment Problem (GAP) is to assign a set of jobs
+   to a set of agents subject to the constraints that each job must be
+   assigned exactly to one agent and the total resources consumed by all
+   jobs assigned to an agent must not exceed the agent's capacity. */
+
+param m, integer, > 0;
+/* number of agents */
+
+param n, integer, > 0;
+/* number of jobs */
+
+set I := 1..m;
+/* set of agents */
+
+set J := 1..n;
+/* set of jobs */
+
+param a{i in I, j in J}, >= 0;
+/* resource consumed in allocating job j to agent i */
+
+param b{i in I}, >= 0;
+/* resource capacity of agent i */
+
+param c{i in I, j in J}, >= 0;
+/* cost of allocating job j to agent i */
+
+var x{i in I, j in J}, binary;
+/* x[i,j] = 1 means job j is assigned to agent i */
+
+s.t. one{j in J}: sum{i in I} x[i,j] = 1;
+/* job j must be assigned exactly to one agent */
+
+s.t. lim{i in I}: sum{j in J} a[i,j] * x[i,j] <= b[i];
+/* total amount of resources consumed by all jobs assigned to agent i
+   must not exceed the agent's capacity */
+
+minimize obj: sum{i in I, j in J} c[i,j] * x[i,j];
+/* the objective is to find cheapest assignment (note that gap can also
+   be formulated as maximization problem) */
+
+data;
+
+/* These data correspond to the instance c515-1 (gap1) from:
+
+   I.H. Osman, "Heuristics for the Generalised Assignment Problem:
+   Simulated Annealing and Tabu Search Approaches", OR Spektrum, Volume
+   17, 211-225, 1995
+
+   D. Cattrysse, M. Salomon and L.N. Van Wassenhove, "A set partitioning
+   heuristic for the generalized assignment problem", European Journal
+   of Operational Research, Volume 72, 167-174, 1994 */
+
+/* The optimal solution is 261 (minimization) or 336 (maximization) */
+
+param m := 5;
+
+param n := 15;
+
+param a :  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 :=
+      1    8 15 14 23  8 16  8 25  9 17 25 15 10  8 24
+      2   15  7 23 22 11 11 12 10 17 16  7 16 10 18 22
+      3   21 20  6 22 24 10 24  9 21 14 11 14 11 19 16
+      4   20 11  8 14  9  5  6 19 19  7  6  6 13  9 18
+      5    8 13 13 13 10 20 25 16 16 17 10 10  5 12 23 ;
+
+param b := 1 36, 2 34, 3 38, 4 27, 5 33;
+
+param c :  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 :=
+      1   17 21 22 18 24 15 20 18 19 18 16 22 24 24 16
+      2   23 16 21 16 17 16 19 25 18 21 17 15 25 17 24
+      3   16 20 16 25 24 16 17 19 19 18 20 16 17 21 24
+      4   19 19 22 22 20 16 19 17 21 19 25 23 25 25 25
+      5   18 19 15 15 21 25 16 16 23 15 22 17 19 22 24 ;
+
+end;
Index: deps/glpk/examples/glpsol.c
===================================================================
--- deps/glpk/examples/glpsol.c	(revision 9)
+++ deps/glpk/examples/glpsol.c	(revision 9)
@@ -0,0 +1,10 @@
+/* glpsol.c */
+
+#include <glpk.h>
+
+int main(int argc, const char *argv[])
+{     /* stand-alone LP/MIP solver */
+      return glp_main(argc, argv);
+}
+
+/* eof */
Index: deps/glpk/examples/graph.mod
===================================================================
--- deps/glpk/examples/graph.mod	(revision 9)
+++ deps/glpk/examples/graph.mod	(revision 9)
@@ -0,0 +1,98 @@
+/* graph.mod - graph visualization */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* This model creates a picture in EPS format to visualize a graph. */
+
+param file, symbolic, default "graph.eps";
+/* output file to write the picture */
+
+param R, default 2;
+/* radius to draw vertices, in mm */
+
+param n, integer, > 0;
+/* number of vertices */
+
+set V, default 1..n;
+/* set of vertices */
+
+set E, within V cross V;
+/* set of edges */
+
+param x{i in V}, default 50 * cos((i - 1) / card(V) * 8 * atan(1));
+param y{i in V}, default 50 * sin((i - 1) / card(V) * 8 * atan(1));
+/* x[i] and y[i] are coordinates of node i, in mm */
+
+param x0 := (min{i in V} x[i]) - R - 3.0;
+param y0 := (min{i in V} y[i]) - R - 3.0;
+param x1 := (max{i in V} x[i]) + R + 3.0;
+param y1 := (max{i in V} y[i]) + R + 3.0;
+
+printf "%%!PS-Adobe-3.0 EPSF-3.0\n" > file;
+printf "%%%%BoundingBox: 0 0 %d %d\n",
+      (72 / 25.4) * (x1 - x0), (72 / 25.4) * (y1 - y0) >> file;
+printf "/Helvetica findfont 6 scalefont setfont\n" >> file;
+printf "/mm { 72 mul 25.4 div } def\n" >> file;
+
+for {(i,j) in E}
+{     printf "newpath\n" >> file;
+      printf "%g mm %g mm moveto\n", x[i] - x0, y[i] - y0 >> file;
+      printf "%g mm %g mm lineto\n", x[j] - x0, y[j] - y0 >> file;
+      printf "closepath\n" >> file;
+      printf "stroke\n" >> file;
+}
+
+for {i in V}
+{     printf "newpath\n" >> file;
+      printf "%g mm %g mm %g mm 0 360 arc\n",
+         x[i] - x0, y[i] - y0, R >> file;
+      printf "closepath\n" >> file;
+      printf "gsave 1 1 1 setrgbcolor fill grestore\n" >> file;
+      printf "stroke\n" >> file;
+      printf "%g mm %g mm moveto\n",
+         x[i] - (if i <= 9 then 1.2 else 1.8) - x0,
+         y[i] - 0.8 - y0 >> file;
+      printf "( %d ) show\n", i >> file;
+}
+
+printf "showpage\n" >> file;
+printf "%%%%EOF\n" >> file;
+
+data;
+
+param
+:  V  :  x     y :=
+   1     0    40
+   2    38    12
+   3    24   -32
+   4   -24   -32
+   5   -38    12
+   6   -19    26
+   7    19    26
+   8    31   -10
+   9     0   -32
+  10   -31   -10
+  11    -9    12
+  12     9    12
+  13    14    -5
+  14     0   -15
+  15   -14    -5
+  16     0     0 ;
+
+set E :=
+   (1,*)  6 10 16 12  7
+   (2,*)  7  6 16 13  8
+   (3,*)  8  7 16 14  9
+   (4,*)  9  8 16 15 10
+   (5,*) 10  9 16 11  6
+   (6,*) 14
+   (7,*) 15
+   (8,*) 11
+   (9,*) 12
+  (10,*) 13
+  (11,*) 12 15
+  (12,*) 13
+  (13,*) 14
+  (14,*) 15 ;
+
+end;
Index: deps/glpk/examples/hashi.mod
===================================================================
--- deps/glpk/examples/hashi.mod	(revision 9)
+++ deps/glpk/examples/hashi.mod	(revision 9)
@@ -0,0 +1,168 @@
+/* A solver for the Japanese number-puzzle Hashiwokakero
+ * (http://en.wikipedia.org/wiki/Hashiwokakero)
+ *
+ * Sebastian Nowozin <nowozin@gmail.com>, 13th January 2009
+ */
+
+param n := 25;
+set rows := 1..n;
+set cols := 1..n;
+param givens{rows, cols}, integer, >= 0, <= 8, default 0;
+
+/* Set of vertices as (row,col) coordinates */
+set V := { (i,j) in { rows, cols }: givens[i,j] != 0 };
+
+/* Set of feasible horizontal edges from (i,j) to (k,l) rightwards */
+set Eh := { (i,j,k,l) in { V, V }:
+        i = k and j < l and             # Same row and left to right
+        card({ (s,t) in V: s = i and t > j and t < l }) = 0             # No vertex inbetween
+        };
+
+/* Set of feasible vertical edges from (i,j) to (k,l) downwards */
+set Ev := { (i,j,k,l) in { V, V }:
+        j = l and i < k and             # Same column and top to bottom
+        card({ (s,t) in V: t = j and s > i and s < k }) = 0             # No vertex inbetween
+        };
+
+set E := Eh union Ev;
+
+/* Indicators: use edge once/twice */
+var xe1{E}, binary;
+var xe2{E}, binary;
+
+/* Constraint: Do not use edge or do use once or do use twice */
+s.t. edge_sel{(i,j,k,l) in E}:
+        xe1[i,j,k,l] + xe2[i,j,k,l] <= 1;
+
+/* Constraint: There must be as many edges used as the node value */
+s.t. satisfy_vertex_demand{(s,t) in V}:
+        sum{(i,j,k,l) in E: (i = s and j = t) or (k = s and l = t)}
+                (xe1[i,j,k,l] + 2.0*xe2[i,j,k,l]) = givens[s,t];
+
+/* Constraint: No crossings */
+s.t. no_crossing1{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
+        s < i and u > i and j < t and l > t}:
+        xe1[i,j,k,l] + xe1[s,t,u,v] <= 1;
+s.t. no_crossing2{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
+        s < i and u > i and j < t and l > t}:
+        xe1[i,j,k,l] + xe2[s,t,u,v] <= 1;
+s.t. no_crossing3{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
+        s < i and u > i and j < t and l > t}:
+        xe2[i,j,k,l] + xe1[s,t,u,v] <= 1;
+s.t. no_crossing4{(i,j,k,l) in Eh, (s,t,u,v) in Ev:
+        s < i and u > i and j < t and l > t}:
+        xe2[i,j,k,l] + xe2[s,t,u,v] <= 1;
+
+
+/* Model connectivity by auxiliary network flow problem:
+ * One vertex becomes a target node and all other vertices send a unit flow
+ * to it.  The edge selection variables xe1/xe2 are VUB constraints and
+ * therefore xe1/xe2 select the feasible graph for the max-flow problems.
+ */
+set node_target := { (s,t) in V:
+        card({ (i,j) in V: i < s or (i = s and j < t) }) = 0};
+set node_sources := { (s,t) in V: (s,t) not in node_target };
+
+var flow_forward{ E }, >= 0;
+var flow_backward{ E }, >= 0;
+s.t. flow_conservation{ (s,t) in node_target, (p,q) in V }:
+        /* All incoming flows */
+        - sum{(i,j,k,l) in E: k = p and l = q} flow_forward[i,j,k,l]
+        - sum{(i,j,k,l) in E: i = p and j = q} flow_backward[i,j,k,l]
+        /* All outgoing flows */
+        + sum{(i,j,k,l) in E: k = p and l = q} flow_backward[i,j,k,l]
+        + sum{(i,j,k,l) in E: i = p and j = q} flow_forward[i,j,k,l]
+        = 0 + (if (p = s and q = t) then card(node_sources) else -1);
+
+/* Variable-Upper-Bound (VUB) constraints: xe1/xe2 bound the flows.
+ */
+s.t. connectivity_vub1{(i,j,k,l) in E}:
+        flow_forward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
+s.t. connectivity_vub2{(i,j,k,l) in E}:
+        flow_backward[i,j,k,l] <= card(node_sources)*(xe1[i,j,k,l] + xe2[i,j,k,l]);
+
+/* A feasible solution is enough
+ */
+minimize cost: 0;
+
+solve;
+
+/* Output solution graphically */
+printf "\nSolution:\n";
+for { row in rows } {
+        for { col in cols } {
+                /* First print this cell information: givens or space */
+                printf{0..0: givens[row,col] != 0} "%d", givens[row,col];
+                printf{0..0: givens[row,col] = 0 and
+                        card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
+                                xe1[i,j,k,l] = 1}) = 1} "-";
+                printf{0..0: givens[row,col] = 0 and
+                        card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
+                                xe2[i,j,k,l] = 1}) = 1} "=";
+                printf{0..0: givens[row,col] = 0
+                        and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
+                                xe1[i,j,k,l] = 1}) = 1} "|";
+                printf{0..0: givens[row,col] = 0
+                        and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
+                                xe2[i,j,k,l] = 1}) = 1} '"';
+                printf{0..0: givens[row,col] = 0
+                        and card({(i,j,k,l) in Eh: i = row and col >= j and col < l and
+                                (xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0
+                        and card({(i,j,k,l) in Ev: j = col and row >= i and row < k and
+                                (xe1[i,j,k,l] = 1 or xe2[i,j,k,l] = 1)}) = 0} " ";
+
+                /* Now print any edges */
+                printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe1[i,j,k,l] = 1} "-";
+                printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and xe2[i,j,k,l] = 1} "=";
+
+                printf{(i,j,k,l) in Eh: i = row and col >= j and col < l and
+                        xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
+                printf{0..0: card({(i,j,k,l) in Eh: i = row and col >= j and col < l}) = 0} " ";
+        }
+        printf "\n";
+        for { col in cols } {
+                printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe1[i,j,k,l] = 1} "|";
+                printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and xe2[i,j,k,l] = 1} '"';
+                printf{(i,j,k,l) in Ev: j = col and row >= i and row < k and
+                        xe1[i,j,k,l] = 0 and xe2[i,j,k,l] = 0} " ";
+                /* No vertical edges: skip also a field */
+                printf{0..0: card({(i,j,k,l) in Ev: j = col and row >= i and row < k}) = 0} " ";
+                printf " ";
+        }
+        printf "\n";
+}
+
+data;
+
+/* This is a difficult 25x25 Hashiwokakero.
+ */
+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
+25 :=
+           1   2 . 2 . 2 . . 2 . 2 . . 2 . . . . 2 . 2 . 2 . 2 .
+           2   . 1 . . . . 2 . . . 4 . . 5 . 2 . . 1 . 2 . 2 . 1
+           3   2 . . 5 . 4 . . 3 . . . . . 1 . . 4 . 5 . 1 . 1 .
+           4   . . . . . . . . . . . 1 . 3 . . 1 . . . . . . . .
+           5   2 . . 6 . 6 . . 8 . 5 . 2 . . 3 . 5 . 7 . . 2 . .
+           6   . 1 . . . . . . . . . 1 . . 2 . . . . . 1 . . . 3
+           7   2 . . . . 5 . . 6 . 4 . . 2 . . . 2 . 5 . 4 . 2 .
+           8   . 2 . 2 . . . . . . . . . . . 3 . . 3 . . . 1 . 2
+           9   . . . . . . . . . . 4 . 2 . 2 . . 1 . . . 3 . 1 .
+          10   2 . 3 . . 6 . . 2 . . . . . . . . . . 3 . . . . .
+          11   . . . . 1 . . 2 . . 5 . . 1 . 4 . 3 . . . . 2 . 4
+          12   . . 2 . . 1 . . . . . . 5 . 4 . . . . 4 . 3 . . .
+          13   2 . . . 3 . 1 . . . . . . . . 3 . . 5 . 5 . . 2 .
+          14   . . . . . 2 . 5 . . 7 . 5 . 3 . 1 . . 1 . . 1 . 4
+          15   2 . 5 . 3 . . . . 1 . 2 . 1 . . . . 2 . 4 . . 2 .
+          16   . . . . . 1 . . . . . . . . . . 2 . . 2 . 1 . . 3
+          17   2 . 6 . 6 . . 2 . . 2 . 2 . 5 . . . . . 2 . . . .
+          18   . . . . . 1 . . . 3 . . . . . 1 . . 1 . . 4 . 3 .
+          19   . . 4 . 5 . . 2 . . . 2 . . 6 . 6 . . 3 . . . . 3
+          20   2 . . . . . . . . . 2 . . 1 . . . . . . 1 . . 1 .
+          21   . . 3 . . 3 . 5 . 5 . . 4 . 6 . 7 . . 4 . 6 . . 4
+          22   2 . . . 3 . 5 . 2 . 1 . . . . . . . . . . . . . .
+          23   . . . . . . . . . 1 . . . . . . 3 . 2 . . 5 . . 5
+          24   2 . 3 . 3 . 5 . 4 . 3 . 3 . 4 . . 2 . 2 . . . 1 .
+          25   . 1 . 2 . 2 . . . 2 . 2 . . . 2 . . . . 2 . 2 . 2
+           ;
+
+end;
Index: deps/glpk/examples/huge.mod
===================================================================
--- deps/glpk/examples/huge.mod	(revision 9)
+++ deps/glpk/examples/huge.mod	(revision 9)
@@ -0,0 +1,25 @@
+/*Arithmetic Mean of a large number of Integers
+  - or - solve a very large constraint matrix
+         over 1 million rows and columns
+  Nigel_Galloway@operamail.com
+  March 18th., 2008.
+*/
+
+param e := 20;
+/* set Sample := {-2**e..2**e-1}; */
+set Sample := {1..2**e-1};
+
+var Mean;
+var E{z in Sample};
+
+/* sum of variances is zero */
+zumVariance: sum{z in Sample} E[z] = 0;
+
+/* Mean + variance[n] = Sample[n] */
+variances{z in Sample}: Mean + E[z] = z;
+
+solve;
+
+printf "The arithmetic mean of the integers from 1 to %d is %f\n", 2**e-1, Mean;
+
+end;
Index: deps/glpk/examples/iptsamp.c
===================================================================
--- deps/glpk/examples/iptsamp.c	(revision 9)
+++ deps/glpk/examples/iptsamp.c	(revision 9)
@@ -0,0 +1,17 @@
+/* iptsamp.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *P;
+      P = glp_create_prob();
+      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
+      glp_interior(P, NULL);
+      glp_print_ipt(P, "25fv47.txt");
+      glp_delete_prob(P);
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/examples/jssp.mod
===================================================================
--- deps/glpk/examples/jssp.mod	(revision 9)
+++ deps/glpk/examples/jssp.mod	(revision 9)
@@ -0,0 +1,114 @@
+/* JSSP, Job-Shop Scheduling Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Job-Shop Scheduling Problem (JSSP) is to schedule a set of jobs
+   on a set of machines, subject to the constraint that each machine can
+   handle at most one job at a time and the fact that each job has a
+   specified processing order through the machines. The objective is to
+   schedule the jobs so as to minimize the maximum of their completion
+   times.
+
+   Reference:
+   D. Applegate and W. Cook, "A Computational Study of the Job-Shop
+   Scheduling Problem", ORSA J. On Comput., Vol. 3, No. 2, Spring 1991,
+   pp. 149-156. */
+
+param n, integer, > 0;
+/* number of jobs */
+
+param m, integer, > 0;
+/* number of machines */
+
+set J := 1..n;
+/* set of jobs */
+
+set M := 1..m;
+/* set of machines */
+
+param sigma{j in J, t in 1..m}, in M;
+/* permutation of the machines, which represents the processing order
+   of j through the machines: j must be processed first on sigma[j,1],
+   then on sigma[j,2], etc. */
+
+check{j in J, t1 in 1..m, t2 in 1..m: t1 <> t2}:
+      sigma[j,t1] != sigma[j,t2];
+/* sigma must be permutation */
+
+param p{j in J, a in M}, >= 0;
+/* processing time of j on a */
+
+var x{j in J, a in M}, >= 0;
+/* starting time of j on a */
+
+s.t. ord{j in J, t in 2..m}:
+      x[j, sigma[j,t]] >= x[j, sigma[j,t-1]] + p[j, sigma[j,t-1]];
+/* j can be processed on sigma[j,t] only after it has been completely
+   processed on sigma[j,t-1] */
+
+/* The disjunctive condition that each machine can handle at most one
+   job at a time is the following:
+
+      x[i,a] >= x[j,a] + p[j,a]  or  x[j,a] >= x[i,a] + p[i,a]
+
+   for all i, j in J, a in M. This condition is modeled through binary
+   variables Y as shown below. */
+
+var Y{i in J, j in J, a in M}, binary;
+/* Y[i,j,a] is 1 if i scheduled before j on machine a, and 0 if j is
+   scheduled before i */
+
+param K := sum{j in J, a in M} p[j,a];
+/* some large constant */
+
+display K;
+
+s.t. phi{i in J, j in J, a in M: i <> j}:
+      x[i,a] >= x[j,a] + p[j,a] - K * Y[i,j,a];
+/* x[i,a] >= x[j,a] + p[j,a] iff Y[i,j,a] is 0 */
+
+s.t. psi{i in J, j in J, a in M: i <> j}:
+      x[j,a] >= x[i,a] + p[i,a] - K * (1 - Y[i,j,a]);
+/* x[j,a] >= x[i,a] + p[i,a] iff Y[i,j,a] is 1 */
+
+var z;
+/* so-called makespan */
+
+s.t. fin{j in J}: z >= x[j, sigma[j,m]] + p[j, sigma[j,m]];
+/* which is the maximum of the completion times of all the jobs */
+
+minimize obj: z;
+/* the objective is to make z as small as possible */
+
+data;
+
+/* These data correspond to the instance ft06 (mt06) from:
+
+   H. Fisher, G.L. Thompson (1963), Probabilistic learning combinations
+   of local job-shop scheduling rules, J.F. Muth, G.L. Thompson (eds.),
+   Industrial Scheduling, Prentice Hall, Englewood Cliffs, New Jersey,
+   225-251 */
+
+/* The optimal solution is 55 */
+
+param n := 6;
+
+param m := 6;
+
+param sigma :  1  2  3  4  5  6 :=
+          1    3  1  2  4  6  5
+          2    2  3  5  6  1  4
+          3    3  4  6  1  2  5
+          4    2  1  3  4  5  6
+          5    3  2  5  6  1  4
+          6    2  4  6  1  5  3 ;
+
+param p     :  1  2  3  4  5  6 :=
+          1    3  6  1  7  6  3
+          2   10  8  5  4 10 10
+          3    9  1  5  4  7  8
+          4    5  5  5  3  8  9
+          5    3  3  9  1  5  4
+          6   10  3  1  3  4  9 ;
+
+end;
Index: deps/glpk/examples/magic.mod
===================================================================
--- deps/glpk/examples/magic.mod	(revision 9)
+++ deps/glpk/examples/magic.mod	(revision 9)
@@ -0,0 +1,54 @@
+/* MAGIC, Magic Square */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* In recreational mathematics, a magic square of order n is an
+   arrangement of n^2 numbers, usually distinct integers, in a square,
+   such that n numbers in all rows, all columns, and both diagonals sum
+   to the same constant. A normal magic square contains the integers
+   from 1 to n^2.
+
+   (From Wikipedia, the free encyclopedia.) */
+
+param n, integer, > 0, default 4;
+/* square order */
+
+set N := 1..n^2;
+/* integers to be placed */
+
+var x{i in 1..n, j in 1..n, k in N}, binary;
+/* x[i,j,k] = 1 means that cell (i,j) contains integer k */
+
+s.t. a{i in 1..n, j in 1..n}: sum{k in N} x[i,j,k] = 1;
+/* each cell must be assigned exactly one integer */
+
+s.t. b{k in N}: sum{i in 1..n, j in 1..n} x[i,j,k] = 1;
+/* each integer must be assigned exactly to one cell */
+
+var s;
+/* the magic sum */
+
+s.t. r{i in 1..n}: sum{j in 1..n, k in N} k * x[i,j,k] = s;
+/* the sum in each row must be the magic sum */
+
+s.t. c{j in 1..n}: sum{i in 1..n, k in N} k * x[i,j,k] = s;
+/* the sum in each column must be the magic sum */
+
+s.t. d: sum{i in 1..n, k in N} k * x[i,i,k] = s;
+/* the sum in the diagonal must be the magic sum */
+
+s.t. e: sum{i in 1..n, k in N} k * x[i,n-i+1,k] = s;
+/* the sum in the co-diagonal must be the magic sum */
+
+solve;
+
+printf "\n";
+printf "Magic sum is %d\n", s;
+printf "\n";
+for{i in 1..n}
+{  printf{j in 1..n} "%3d", sum{k in N} k * x[i,j,k];
+   printf "\n";
+}
+printf "\n";
+
+end;
Index: deps/glpk/examples/maxcut.mod
===================================================================
--- deps/glpk/examples/maxcut.mod	(revision 9)
+++ deps/glpk/examples/maxcut.mod	(revision 9)
@@ -0,0 +1,85 @@
+/* MAXCUT, Maximum Cut Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Maximum Cut Problem in a network G = (V, E), where V is a set
+   of nodes, E is a set of edges, is to find the partition of V into
+   disjoint sets V1 and V2, which maximizes the sum of edge weights
+   w(e), where edge e has one endpoint in V1 and other endpoint in V2.
+
+   Reference:
+   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
+   A guide to the theory of NP-completeness [Network design, Cuts and
+   Connectivity, Maximum Cut, ND16]. */
+
+set E, dimen 2;
+/* set of edges */
+
+param w{(i,j) in E}, >= 0, default 1;
+/* w[i,j] is weight of edge (i,j) */
+
+set V := (setof{(i,j) in E} i) union (setof{(i,j) in E} j);
+/* set of nodes */
+
+var x{i in V}, binary;
+/* x[i] = 0 means that node i is in set V1
+   x[i] = 1 means that node i is in set V2 */
+
+/* We need to include in the objective function only that edges (i,j)
+   from E, for which x[i] != x[j]. This can be modeled through binary
+   variables s[i,j] as follows:
+
+      s[i,j] = x[i] xor x[j] = (x[i] + x[j]) mod 2,                  (1)
+
+   where s[i,j] = 1 iff x[i] != x[j], that leads to the following
+   objective function:
+
+      z = sum{(i,j) in E} w[i,j] * s[i,j].                           (2)
+
+   To describe "exclusive or" (1) we could think that s[i,j] is a minor
+   bit of the sum x[i] + x[j]. Then introducing binary variables t[i,j],
+   which represent a major bit of the sum x[i] + x[j], we can write:
+
+      x[i] + x[j] = s[i,j] + 2 * t[i,j].                             (3)
+
+   An easy check shows that conditions (1) and (3) are equivalent.
+
+   Note that condition (3) can be simplified by eliminating variables
+   s[i,j]. Indeed, from (3) it follows that:
+
+      s[i,j] = x[i] + x[j] - 2 * t[i,j].                             (4)
+
+   Since the expression in the right-hand side of (4) is integral, this
+   condition can be rewritten in the equivalent form:
+
+      0 <= x[i] + x[j] - 2 * t[i,j] <= 1.                            (5)
+
+   (One might note that (5) means t[i,j] = x[i] and x[j].)
+
+   Substituting s[i,j] from (4) to (2) leads to the following objective
+   function:
+
+      z = sum{(i,j) in E} w[i,j] * (x[i] + x[j] - 2 * t[i,j]),       (6)
+
+   which does not include variables s[i,j]. */
+
+var t{(i,j) in E}, binary;
+/* t[i,j] = x[i] and x[j] = (x[i] + x[j]) div 2 */
+
+s.t. xor{(i,j) in E}: 0 <= x[i] + x[j] - 2 * t[i,j] <= 1;
+/* see (4) */
+
+maximize z: sum{(i,j) in E} w[i,j] * (x[i] + x[j] - 2 * t[i,j]);
+/* see (6) */
+
+data;
+
+/* In this example the network has 15 nodes and 22 edges. */
+
+/* Optimal solution is 20 */
+
+set E :=
+   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,
+   8 12, 9 10, 9 14, 10 11, 10 14, 11 15, 12 13, 13 14, 14 15;
+
+end;
Index: deps/glpk/examples/maxflow.mod
===================================================================
--- deps/glpk/examples/maxflow.mod	(revision 9)
+++ deps/glpk/examples/maxflow.mod	(revision 9)
@@ -0,0 +1,83 @@
+/* MAXFLOW, Maximum Flow Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Maximum Flow Problem in a network G = (V, E), where V is a set
+   of nodes, E within V x V is a set of arcs, is to maximize the flow
+   from one given node s (source) to another given node t (sink) subject
+   to conservation of flow constraints at each node and flow capacities
+   on each arc. */
+
+param n, integer, >= 2;
+/* number of nodes */
+
+set V, default {1..n};
+/* set of nodes */
+
+set E, within V cross V;
+/* set of arcs */
+
+param a{(i,j) in E}, > 0;
+/* a[i,j] is capacity of arc (i,j) */
+
+param s, symbolic, in V, default 1;
+/* source node */
+
+param t, symbolic, in V, != s, default n;
+/* sink node */
+
+var x{(i,j) in E}, >= 0, <= a[i,j];
+/* x[i,j] is elementary flow through arc (i,j) to be found */
+
+var flow, >= 0;
+/* total flow from s to t */
+
+s.t. node{i in V}:
+/* node[i] is conservation constraint for node i */
+
+   sum{(j,i) in E} x[j,i] + (if i = s then flow)
+   /* summary flow into node i through all ingoing arcs */
+
+   = /* must be equal to */
+
+   sum{(i,j) in E} x[i,j] + (if i = t then flow);
+   /* summary flow from node i through all outgoing arcs */
+
+maximize obj: flow;
+/* objective is to maximize the total flow through the network */
+
+solve;
+
+printf{1..56} "="; printf "\n";
+printf "Maximum flow from node %s to node %s is %g\n\n", s, t, flow;
+printf "Starting node   Ending node   Arc capacity   Flow in arc\n";
+printf "-------------   -----------   ------------   -----------\n";
+printf{(i,j) in E: x[i,j] != 0}: "%13s   %11s   %12g   %11g\n", i, j,
+   a[i,j], x[i,j];
+printf{1..56} "="; printf "\n";
+
+data;
+
+/* These data correspond to an example from [Christofides]. */
+
+/* Optimal solution is 29 */
+
+param n := 9;
+
+param : E :   a :=
+       1 2   14
+       1 4   23
+       2 3   10
+       2 4    9
+       3 5   12
+       3 8   18
+       4 5   26
+       5 2   11
+       5 6   25
+       5 7    4
+       6 7    7
+       6 8    8
+       7 9   15
+       8 9   20;
+
+end;
Index: deps/glpk/examples/mfasp.mod
===================================================================
--- deps/glpk/examples/mfasp.mod	(revision 9)
+++ deps/glpk/examples/mfasp.mod	(revision 9)
@@ -0,0 +1,62 @@
+/* MFASP, Minimum Feedback Arc Set Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Minimum Feedback Arc Set Problem for a given directed graph
+   G = (V, E), where V is a set of vertices and E is a set of arcs, is
+   to find a minimal subset of arcs, which being removed from the graph
+   make it acyclic.
+
+   Reference:
+   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
+   A guide to the theory of NP-completeness [Graph Theory, Covering and
+   Partitioning, Minimum Feedback Arc Set, GT9]. */
+
+param n, integer, >= 0;
+/* number of vertices */
+
+set V, default 1..n;
+/* set of vertices */
+
+set E, within V cross V,
+default setof{i in V, j in V: i <> j and Uniform(0,1) <= 0.15} (i,j);
+/* set of arcs */
+
+printf "Graph has %d vertices and %d arcs\n", card(V), card(E);
+
+var x{(i,j) in E}, binary;
+/* x[i,j] = 1 means that (i->j) is a feedback arc */
+
+/* It is known that a digraph G = (V, E) is acyclic if and only if its
+   vertices can be assigned numbers from 1 to |V| in such a way that
+   k[i] + 1 <= k[j] for every arc (i->j) in E, where k[i] is a number
+   assigned to vertex i. We may use this condition to require that the
+   digraph G = (V, E \ E'), where E' is a subset of feedback arcs, is
+   acyclic. */
+
+var k{i in V}, >= 1, <= card(V);
+/* k[i] is a number assigned to vertex i */
+
+s.t. r{(i,j) in E}: k[j] - k[i] >= 1 - card(V) * x[i,j];
+/* note that x[i,j] = 1 leads to a redundant constraint */
+
+minimize obj: sum{(i,j) in E} x[i,j];
+/* the objective is to minimize the cardinality of a subset of feedback
+   arcs */
+
+solve;
+
+printf "Minimum feedback arc set:\n";
+printf{(i,j) in E: x[i,j]} "%d %d\n", i, j;
+
+data;
+
+/* The optimal solution is 3 */
+
+param n := 15;
+
+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,
+         10 11, 10 14, 11 15, 12 7, 12 8, 12 13, 13 8, 13 12, 13 14,
+         14 9, 15 14;
+
+end;
Index: deps/glpk/examples/mfvsp.mod
===================================================================
--- deps/glpk/examples/mfvsp.mod	(revision 9)
+++ deps/glpk/examples/mfvsp.mod	(revision 9)
@@ -0,0 +1,62 @@
+/* MFVSP, Minimum Feedback Vertex Set Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Minimum Feedback Vertex Set Problem for a given directed graph
+   G = (V, E), where V is a set of vertices and E is a set of arcs, is
+   to find a minimal subset of vertices, which being removed from the
+   graph make it acyclic.
+
+   Reference:
+   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
+   A guide to the theory of NP-completeness [Graph Theory, Covering and
+   Partitioning, Minimum Feedback Vertex Set, GT8]. */
+
+param n, integer, >= 0;
+/* number of vertices */
+
+set V, default 1..n;
+/* set of vertices */
+
+set E, within V cross V,
+default setof{i in V, j in V: i <> j and Uniform(0,1) <= 0.15} (i,j);
+/* set of arcs */
+
+printf "Graph has %d vertices and %d arcs\n", card(V), card(E);
+
+var x{i in V}, binary;
+/* x[i] = 1 means that i is a feedback vertex */
+
+/* It is known that a digraph G = (V, E) is acyclic if and only if its
+   vertices can be assigned numbers from 1 to |V| in such a way that
+   k[i] + 1 <= k[j] for every arc (i->j) in E, where k[i] is a number
+   assigned to vertex i. We may use this condition to require that the
+   digraph G = (V, E \ E'), where E' is a subset of feedback arcs, is
+   acyclic. */
+
+var k{i in V}, >= 1, <= card(V);
+/* k[i] is a number assigned to vertex i */
+
+s.t. r{(i,j) in E}: k[j] - k[i] >= 1 - card(V) * (x[i] + x[j]);
+/* note that x[i] = 1 or x[j] = 1 leads to a redundant constraint */
+
+minimize obj: sum{i in V} x[i];
+/* the objective is to minimize the cardinality of a subset of feedback
+   vertices */
+
+solve;
+
+printf "Minimum feedback vertex set:\n";
+printf{i in V: x[i]} "%d\n", i;
+
+data;
+
+/* The optimal solution is 3 */
+
+param n := 15;
+
+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,
+         10 11, 10 14, 11 15, 12 7, 12 8, 12 13, 13 8, 13 12, 13 14,
+         14 9, 15 14;
+
+end;
Index: deps/glpk/examples/min01ks.mod
===================================================================
--- deps/glpk/examples/min01ks.mod	(revision 9)
+++ deps/glpk/examples/min01ks.mod	(revision 9)
@@ -0,0 +1,111 @@
+/* min01ks.mod - finding minimal equivalent 0-1 knapsack inequality */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* It is obvious that for a given 0-1 knapsack inequality
+
+      a[1] x[1] + ... + a[n] x[n] <= b,  x[j] in {0, 1}              (1)
+
+   there exist infinitely many equivalent inequalities with exactly the
+   same feasible solutions.
+
+   Given a[j]'s and b this model allows to find an inequality
+
+      alfa[1] x[1] + ... + alfa[n] x[n] <= beta,  x[j] in {0, 1},    (2)
+
+   which is equivalent to (1) and where alfa[j]'s and beta are smallest
+   non-negative integers.
+
+   This model has the following formulation:
+
+      minimize
+
+         z = |alfa[1]| + ... + |alfa[n]| + |beta| =                  (3)
+
+           = alfa[1] + ... + alfa[n] + beta
+
+      subject to
+
+         alfa[1] x[1] + ... + alfa[n] x[n] <= beta                   (4)
+
+                              for all x satisfying to (1)
+
+         alfa[1] x[1] + ... + alfa[n] x[n] >= beta + 1               (5)
+
+                              for all x not satisfying to (1)
+
+         alfa[1], ..., alfa[n], beta are non-negative integers.
+
+   Note that this model has n+1 variables and 2^n constraints.
+
+   It is interesting, as noticed in [1] and explained in [2], that
+   in most cases LP relaxation of the MIP formulation above has integer
+   optimal solution.
+
+   References
+
+   1. G.H.Bradley, P.L.Hammer, L.Wolsey, "Coefficient Reduction for
+      Inequalities in 0-1 Variables", Math.Prog.7 (1974), 263-282.
+
+   2. G.J.Koehler, "A Study on Coefficient Reduction of Binary Knapsack
+      Inequalities", University of Florida, 2001. */
+
+param n, integer, > 0;
+/* number of variables in the knapsack inequality */
+
+set N := 1..n;
+/* set of knapsack items */
+
+/* all binary n-vectors are numbered by 0, 1, ..., 2^n-1, where vector
+   0 is 00...00, vector 1 is 00...01, etc. */
+
+set U := 0..2^n-1;
+/* set of numbers of all binary n-vectors */
+
+param x{i in U, j in N}, binary, := (i div 2^(j-1)) mod 2;
+/* x[i,j] is j-th component of i-th binary n-vector */
+
+param a{j in N}, >= 0;
+/* original coefficients */
+
+param b, >= 0;
+/* original right-hand side */
+
+set D := setof{i in U: sum{j in N} a[j] * x[i,j] <= b} i;
+/* set of numbers of binary n-vectors, which (vectors) are feasible,
+   i.e. satisfy to the original knapsack inequality (1) */
+
+var alfa{j in N}, integer, >= 0;
+/* coefficients to be found */
+
+var beta, integer, >= 0;
+/* right-hand side to be found */
+
+minimize z: sum{j in N} alfa[j] + beta; /* (3) */
+
+phi{i in D}: sum{j in N} alfa[j] * x[i,j] <= beta; /* (4) */
+
+psi{i in U diff D}: sum{j in N} alfa[j] * x[i,j] >= beta + 1; /* (5) */
+
+solve;
+
+printf "\nOriginal 0-1 knapsack inequality:\n";
+for {j in 1..n} printf (if j = 1 then "" else " + ") & "%g x%d",
+   a[j], j;
+printf " <= %g\n", b;
+printf "\nMinimized equivalent inequality:\n";
+for {j in 1..n} printf (if j = 1 then "" else " + ") & "%g x%d",
+   alfa[j], j;
+printf " <= %g\n\n", beta;
+
+data;
+
+/* These data correspond to the very first example from [1]. */
+
+param n := 8;
+
+param a := [1]65, [2]64, [3]41, [4]22, [5]13, [6]12, [7]8, [8]2;
+
+param b := 80;
+
+end;
Index: deps/glpk/examples/misp.mod
===================================================================
--- deps/glpk/examples/misp.mod	(revision 9)
+++ deps/glpk/examples/misp.mod	(revision 9)
@@ -0,0 +1,665 @@
+/* MISP, Maximum Independent Set Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* Let G = (V,E) be an undirected graph with vertex set V and edge set
+   E. Vertices u, v in V are non-adjacent if (u,v) not in E. A subset
+   of the vertices S within V is independent if all vertices in S are
+   pairwise non-adjacent. The Maximum Independent Set Problem (MISP) is
+   to find an independent set having the largest cardinality. */
+
+param n, integer, > 0;
+/* number of vertices */
+
+set V := 1..n;
+/* set of vertices */
+
+set E within V cross V;
+/* set of edges */
+
+var x{i in V}, binary;
+/* x[i] = 1 means vertex i belongs to independent set */
+
+s.t. edge{(i,j) in E}: x[i] + x[j] <= 1;
+/* if there is edge (i,j), vertices i and j cannot belong to the same
+   independent set */
+
+maximize obj: sum{i in V} x[i];
+/* the objective is to maximize the cardinality of independent set */
+
+data;
+
+/* These data corresponds to the test instance from:
+
+   M.G.C. Resende, T.A.Feo, S.H.Smith, "Algorithm 787 -- FORTRAN
+   subroutines for approximate solution of the maximum independent set
+   problem using GRASP," Trans. on Math. Softw., Vol. 24, No. 4,
+   December 1998, pp. 386-394. */
+
+/* The optimal solution is 7 */
+
+param n := 50;
+
+set E :=
+ 1 2
+ 1 3
+ 1 5
+ 1 7
+ 1 8
+ 1 12
+ 1 15
+ 1 16
+ 1 19
+ 1 20
+ 1 21
+ 1 22
+ 1 28
+ 1 30
+ 1 34
+ 1 35
+ 1 37
+ 1 41
+ 1 42
+ 1 47
+ 1 50
+ 2 3
+ 2 5
+ 2 6
+ 2 7
+ 2 8
+ 2 9
+ 2 10
+ 2 13
+ 2 17
+ 2 19
+ 2 20
+ 2 21
+ 2 23
+ 2 25
+ 2 26
+ 2 29
+ 2 31
+ 2 35
+ 2 36
+ 2 44
+ 2 45
+ 2 46
+ 2 50
+ 3 5
+ 3 6
+ 3 8
+ 3 9
+ 3 10
+ 3 11
+ 3 14
+ 3 16
+ 3 23
+ 3 24
+ 3 26
+ 3 27
+ 3 28
+ 3 29
+ 3 30
+ 3 31
+ 3 34
+ 3 35
+ 3 36
+ 3 39
+ 3 41
+ 3 42
+ 3 43
+ 3 44
+ 3 50
+ 4 6
+ 4 7
+ 4 9
+ 4 10
+ 4 11
+ 4 13
+ 4 14
+ 4 15
+ 4 17
+ 4 21
+ 4 22
+ 4 23
+ 4 24
+ 4 25
+ 4 27
+ 4 28
+ 4 30
+ 4 31
+ 4 33
+ 4 34
+ 4 35
+ 4 36
+ 4 37
+ 4 38
+ 4 40
+ 4 41
+ 4 42
+ 4 46
+ 4 49
+ 5 6
+ 5 11
+ 5 14
+ 5 21
+ 5 24
+ 5 25
+ 5 28
+ 5 35
+ 5 38
+ 5 39
+ 5 41
+ 5 44
+ 5 49
+ 5 50
+ 6 8
+ 6 9
+ 6 10
+ 6 13
+ 6 14
+ 6 16
+ 6 17
+ 6 19
+ 6 22
+ 6 23
+ 6 26
+ 6 27
+ 6 30
+ 6 34
+ 6 35
+ 6 38
+ 6 39
+ 6 40
+ 6 41
+ 6 44
+ 6 45
+ 6 47
+ 6 50
+ 7 8
+ 7 9
+ 7 10
+ 7 11
+ 7 13
+ 7 15
+ 7 16
+ 7 18
+ 7 20
+ 7 22
+ 7 23
+ 7 24
+ 7 25
+ 7 33
+ 7 35
+ 7 36
+ 7 38
+ 7 43
+ 7 45
+ 7 46
+ 7 47
+ 8 10
+ 8 11
+ 8 13
+ 8 16
+ 8 17
+ 8 18
+ 8 19
+ 8 20
+ 8 21
+ 8 22
+ 8 23
+ 8 24
+ 8 25
+ 8 26
+ 8 33
+ 8 35
+ 8 36
+ 8 39
+ 8 42
+ 8 44
+ 8 48
+ 8 49
+ 9 12
+ 9 14
+ 9 17
+ 9 19
+ 9 20
+ 9 23
+ 9 28
+ 9 30
+ 9 31
+ 9 32
+ 9 33
+ 9 34
+ 9 38
+ 9 39
+ 9 42
+ 9 44
+ 9 45
+ 9 46
+ 10 11
+ 10 13
+ 10 15
+ 10 16
+ 10 17
+ 10 20
+ 10 21
+ 10 22
+ 10 23
+ 10 25
+ 10 26
+ 10 27
+ 10 28
+ 10 30
+ 10 31
+ 10 32
+ 10 37
+ 10 38
+ 10 41
+ 10 43
+ 10 44
+ 10 45
+ 10 50
+ 11 12
+ 11 14
+ 11 15
+ 11 18
+ 11 21
+ 11 24
+ 11 25
+ 11 26
+ 11 29
+ 11 32
+ 11 33
+ 11 35
+ 11 36
+ 11 37
+ 11 39
+ 11 40
+ 11 42
+ 11 43
+ 11 45
+ 11 47
+ 11 49
+ 11 50
+ 12 13
+ 12 16
+ 12 17
+ 12 19
+ 12 24
+ 12 25
+ 12 26
+ 12 30
+ 12 31
+ 12 32
+ 12 34
+ 12 36
+ 12 37
+ 12 39
+ 12 41
+ 12 44
+ 12 47
+ 12 48
+ 12 49
+ 13 15
+ 13 16
+ 13 18
+ 13 19
+ 13 20
+ 13 22
+ 13 23
+ 13 24
+ 13 27
+ 13 28
+ 13 29
+ 13 31
+ 13 33
+ 13 35
+ 13 36
+ 13 37
+ 13 44
+ 13 47
+ 13 49
+ 13 50
+ 14 15
+ 14 16
+ 14 17
+ 14 18
+ 14 19
+ 14 20
+ 14 21
+ 14 26
+ 14 28
+ 14 29
+ 14 30
+ 14 31
+ 14 32
+ 14 34
+ 14 35
+ 14 36
+ 14 38
+ 14 39
+ 14 41
+ 14 44
+ 14 46
+ 14 47
+ 14 48
+ 15 18
+ 15 21
+ 15 22
+ 15 23
+ 15 25
+ 15 28
+ 15 29
+ 15 30
+ 15 33
+ 15 34
+ 15 36
+ 15 37
+ 15 38
+ 15 39
+ 15 40
+ 15 43
+ 15 44
+ 15 46
+ 15 50
+ 16 17
+ 16 19
+ 16 20
+ 16 25
+ 16 26
+ 16 29
+ 16 35
+ 16 38
+ 16 39
+ 16 40
+ 16 41
+ 16 42
+ 16 44
+ 17 18
+ 17 19
+ 17 21
+ 17 22
+ 17 23
+ 17 25
+ 17 26
+ 17 28
+ 17 29
+ 17 33
+ 17 37
+ 17 44
+ 17 45
+ 17 48
+ 18 20
+ 18 24
+ 18 27
+ 18 28
+ 18 31
+ 18 32
+ 18 34
+ 18 35
+ 18 36
+ 18 37
+ 18 38
+ 18 45
+ 18 48
+ 18 49
+ 18 50
+ 19 22
+ 19 24
+ 19 28
+ 19 29
+ 19 36
+ 19 37
+ 19 39
+ 19 41
+ 19 43
+ 19 45
+ 19 48
+ 19 49
+ 20 21
+ 20 22
+ 20 24
+ 20 25
+ 20 26
+ 20 27
+ 20 29
+ 20 30
+ 20 31
+ 20 33
+ 20 34
+ 20 35
+ 20 38
+ 20 39
+ 20 41
+ 20 42
+ 20 43
+ 20 44
+ 20 45
+ 20 46
+ 20 48
+ 20 49
+ 21 22
+ 21 23
+ 21 29
+ 21 31
+ 21 35
+ 21 38
+ 21 42
+ 21 46
+ 21 47
+ 22 23
+ 22 26
+ 22 27
+ 22 28
+ 22 29
+ 22 30
+ 22 39
+ 22 40
+ 22 41
+ 22 42
+ 22 44
+ 22 45
+ 22 46
+ 22 47
+ 22 49
+ 22 50
+ 23 28
+ 23 31
+ 23 32
+ 23 33
+ 23 34
+ 23 35
+ 23 36
+ 23 39
+ 23 40
+ 23 41
+ 23 42
+ 23 44
+ 23 45
+ 23 48
+ 23 49
+ 23 50
+ 24 25
+ 24 27
+ 24 29
+ 24 30
+ 24 31
+ 24 33
+ 24 34
+ 24 38
+ 24 42
+ 24 43
+ 24 44
+ 24 49
+ 24 50
+ 25 26
+ 25 27
+ 25 29
+ 25 30
+ 25 33
+ 25 34
+ 25 36
+ 25 38
+ 25 40
+ 25 41
+ 25 42
+ 25 44
+ 25 46
+ 25 47
+ 25 48
+ 25 49
+ 26 28
+ 26 31
+ 26 32
+ 26 33
+ 26 37
+ 26 38
+ 26 39
+ 26 40
+ 26 41
+ 26 42
+ 26 45
+ 26 47
+ 26 48
+ 26 49
+ 27 29
+ 27 30
+ 27 33
+ 27 34
+ 27 35
+ 27 39
+ 27 40
+ 27 46
+ 27 48
+ 28 29
+ 28 37
+ 28 40
+ 28 42
+ 28 44
+ 28 46
+ 28 47
+ 28 50
+ 29 35
+ 29 38
+ 29 39
+ 29 41
+ 29 42
+ 29 48
+ 30 31
+ 30 32
+ 30 35
+ 30 37
+ 30 38
+ 30 40
+ 30 43
+ 30 45
+ 30 46
+ 30 47
+ 30 48
+ 31 33
+ 31 35
+ 31 38
+ 31 40
+ 31 41
+ 31 42
+ 31 44
+ 31 46
+ 31 47
+ 31 50
+ 32 33
+ 32 35
+ 32 39
+ 32 40
+ 32 46
+ 32 49
+ 32 50
+ 33 34
+ 33 36
+ 33 37
+ 33 40
+ 33 42
+ 33 43
+ 33 44
+ 33 45
+ 33 50
+ 34 35
+ 34 36
+ 34 37
+ 34 38
+ 34 40
+ 34 43
+ 34 44
+ 34 49
+ 34 50
+ 35 36
+ 35 38
+ 35 41
+ 35 42
+ 35 43
+ 35 45
+ 35 46
+ 35 47
+ 35 49
+ 35 50
+ 36 37
+ 36 39
+ 36 40
+ 36 41
+ 36 42
+ 36 43
+ 36 48
+ 36 50
+ 37 38
+ 37 41
+ 37 43
+ 37 46
+ 37 47
+ 37 48
+ 37 49
+ 37 50
+ 38 41
+ 38 45
+ 38 46
+ 38 48
+ 38 49
+ 38 50
+ 39 43
+ 39 46
+ 39 47
+ 39 48
+ 39 49
+ 40 43
+ 40 45
+ 40 48
+ 40 50
+ 41 42
+ 41 43
+ 41 44
+ 41 45
+ 41 46
+ 41 48
+ 41 49
+ 42 43
+ 42 44
+ 42 46
+ 42 48
+ 42 49
+ 43 45
+ 43 46
+ 43 48
+ 43 50
+ 44 45
+ 44 48
+ 45 46
+ 45 47
+ 45 48
+ 46 49
+ 47 49
+ 47 50
+ 48 49
+ 48 50
+ 49 50
+;
+
+end;
Index: deps/glpk/examples/money.mod
===================================================================
--- deps/glpk/examples/money.mod	(revision 9)
+++ deps/glpk/examples/money.mod	(revision 9)
@@ -0,0 +1,62 @@
+/* MONEY, a crypto-arithmetic puzzle */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* This is the classic example of a crypto-arithmetic puzzle published
+   in the Strand Magazine by Henry Dudeney:
+
+        S E N D
+      +
+        M O R E
+      ---------
+      M O N E Y
+
+   In this puzzle the same letters mean the same digits. The question
+   is: how to replace all the letters with the respective digits that
+   makes the calculation correct?
+
+   The solution to this puzzle is:
+   O = 0, M = 1, Y = 2, E = 5, N = 6, D = 7, R = 8, and S = 9.
+
+   References:
+   H. E. Dudeney, in Strand Magazine vol. 68 (July 1924), pp. 97, 214.
+
+   (From Wikipedia, the free encyclopedia.) */
+
+set LETTERS := { 'D', 'E', 'M', 'N', 'O', 'R', 'S', 'Y' };
+/* set of letters */
+
+set DIGITS := 0..9;
+/* set of digits */
+
+var x{i in LETTERS, d in DIGITS}, binary;
+/* x[i,d] = 1 means that letter i is digit d */
+
+s.t. one{i in LETTERS}: sum{d in DIGITS} x[i,d] = 1;
+/* each letter must correspond exactly to one digit */
+
+s.t. alldiff{d in DIGITS}: sum{i in LETTERS} x[i,d] <= 1;
+/* different letters must correspond to different digits; note that
+   some digits may not correspond to any letters at all */
+
+var dig{i in LETTERS};
+/* dig[i] is a digit corresponding to letter i */
+
+s.t. map{i in LETTERS}: dig[i] = sum{d in DIGITS} d * x[i,d];
+
+var carry{1..3}, binary;
+/* carry bits */
+
+s.t. sum1: dig['D'] + dig['E']            = dig['Y'] + 10 * carry[1];
+s.t. sum2: dig['N'] + dig['R'] + carry[1] = dig['E'] + 10 * carry[2];
+s.t. sum3: dig['E'] + dig['O'] + carry[2] = dig['N'] + 10 * carry[3];
+s.t. sum4: dig['S'] + dig['M'] + carry[3] = dig['O'] + 10 * dig['M'];
+s.t. note: dig['M'] >= 1; /* M must not be 0 */
+
+solve;
+/* solve the puzzle */
+
+display dig;
+/* and display its solution */
+
+end;
Index: deps/glpk/examples/mplsamp1.c
===================================================================
--- deps/glpk/examples/mplsamp1.c	(revision 9)
+++ deps/glpk/examples/mplsamp1.c	(revision 9)
@@ -0,0 +1,32 @@
+/* mplsamp1.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *lp;
+      glp_tran *tran;
+      int ret;
+      lp = glp_create_prob();
+      tran = glp_mpl_alloc_wksp();
+      ret = glp_mpl_read_model(tran, "egypt.mod", 0);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on translating model\n");
+         goto skip;
+      }
+      ret = glp_mpl_generate(tran, NULL);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on generating model\n");
+         goto skip;
+      }
+      glp_mpl_build_prob(tran, lp);
+      ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, "egypt.mps");
+      if (ret != 0)
+         fprintf(stderr, "Error on writing MPS file\n");
+skip: glp_mpl_free_wksp(tran);
+      glp_delete_prob(lp);
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/examples/mplsamp2.c
===================================================================
--- deps/glpk/examples/mplsamp2.c	(revision 9)
+++ deps/glpk/examples/mplsamp2.c	(revision 9)
@@ -0,0 +1,39 @@
+/* mplsamp2.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *mip;
+      glp_tran *tran;
+      int ret;
+      mip = glp_create_prob();
+      tran = glp_mpl_alloc_wksp();
+      ret = glp_mpl_read_model(tran, "sudoku.mod", 1);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on translating model\n");
+         goto skip;
+      }
+      ret = glp_mpl_read_data(tran, "sudoku.dat");
+      if (ret != 0)
+      {  fprintf(stderr, "Error on translating data\n");
+         goto skip;
+      }
+      ret = glp_mpl_generate(tran, NULL);
+      if (ret != 0)
+      {  fprintf(stderr, "Error on generating model\n");
+         goto skip;
+      }
+      glp_mpl_build_prob(tran, mip);
+      glp_simplex(mip, NULL);
+      glp_intopt(mip, NULL);
+      ret = glp_mpl_postsolve(tran, mip, GLP_MIP);
+      if (ret != 0)
+         fprintf(stderr, "Error on postsolving model\n");
+skip: glp_mpl_free_wksp(tran);
+      glp_delete_prob(mip);
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/examples/murtagh.mps
===================================================================
--- deps/glpk/examples/murtagh.mps	(revision 9)
+++ deps/glpk/examples/murtagh.mps	(revision 9)
@@ -0,0 +1,600 @@
+*NAME:         OIL
+*ROWS:         74
+*COLUMNS:      81
+*NONZERO:      504
+*OPT SOLN:     126.057
+*SOURCE:       Bruce Murtagh, "Advanced Linear Programming"
+*APPLICATION:  oil refinery model
+*COMMENTS:     problem is maximization
+*
+NAME          OIL REFINERY  EXAMPLE
+ROWS
+ N  PROFIT
+ L  MVOLBOL
+ L  MVOLCOL
+ E  MVOLLNC
+ E  MVOLLNB
+ E  MVOLSRK
+ E  MVOLSRD
+ E  MVOLVBB
+ E  MVOLVBC
+ E  MVOLRCR
+ E  MVOLHVO
+ E  UBALKWH
+ E  UBALH2O
+ E  UBALSTM
+ E  UBALFUL
+ E  MVOLB95
+ E  MVOLB90
+ E  MVOLLHG
+ E  MVOLC3S
+ E  MVOLNC4
+ E  MVOLLSR
+ E  MVOLHSR
+ E  MVOLIC4
+ L  VCAPSGP
+ E  MVOLRFG
+ E  MSCFHYL
+ E  MVOLR90
+ E  MVOLR95
+ E  MVOLF90
+ E  MVOLF95
+ L  VCAPRFG
+ E  MVOLLCO
+ E  MVOLHHG
+ E  MVOLHCD
+ L  VCAPHVO
+ L  VCAPHOL
+ E  MVOLC3U
+ E  MVOLC4U
+ E  MVOLFCG
+ E  MVOLSLR
+ L  VCAPCCU
+ E  MVOLLA3
+ E  MVOLLA4
+ L  VCAPALK
+ L  XLPRPRE
+ L  XHPRPRE
+ L  XTELPRE
+ L  XRVPPRE
+ L  X200PRE
+ L  X230PRE
+ E  EVOLPRE
+ L  XPSCPRE
+ L  XRSCREG
+ L  XLPRINT
+ L  XHPRINT
+ L  XTELINT
+ L  XRVPINT
+ L  X200INT
+ L  X230INT
+ E  EVOLINT
+ L  XLPRREG
+ L  XHPRREG
+ L  XTELREG
+ L  XRVPREG
+ L  X200REG
+ L  X230REG
+ E  EVOLREG
+ E  EVOLLPG
+ E  EVOLJP4
+ L  XRVXJP4
+ L  XRVNJP4
+ E  EVOLDSL
+ E  EVOLRSD
+ L  XVISRSD
+COLUMNS
+    VCRDBOL   MVOLBOL   1.0
+    VCRDBOL   MVOLLNB   -.537
+    VCRDBOL   MVOLSRK   -.131
+    VCRDBOL   MVOLSRD   -.1155
+    VCRDBOL   MVOLVBB   -.037
+    VCRDBOL   MVOLRCR   -.0365
+    VCRDBOL   MVOLHVO   -.143
+    VCRDBOL   UBALKWH   .302
+    VCRDBOL   UBALH2O   .150
+    VCRDBOL   UBALSTM   .003
+    VCRDBOL   UBALFUL   .0587
+    VCRDBOL   PROFIT    -12.8
+    VCRDCOL   MVOLCOL   1.
+    VCRDCOL   MVOLLNC   -.2931
+    VCRDCOL   MVOLSRK   -.1170
+    VCRDCOL   MVOLSRD   -.0649
+    VCRDCOL   MVOLVBC   -.18
+    VCRDCOL   MVOLRCR   -.1233
+    VCRDCOL   MVOLHVO   -.2217
+    VCRDCOL   UBALKWH   .384
+    VCRDCOL   UBALH2O   .185
+    VCRDCOL   UBALSTM   .003
+    VCRDCOL   UBALFUL   .1053
+    VCRDCOL   PROFIT    -11.48
+    VSGPLNC   MVOLLNC   1.
+    VSGPLNC   MVOLC3S   -.0112
+    VSGPLNC   MVOLNC4   -.0378
+    VSGPLNC   MVOLLSR   -.1502
+    VSGPLNC   MVOLHSR   -.7953
+    VSGPLNC   MVOLIC4   -.0099
+    VSGPLNC   UBALKWH   .721
+    VSGPLNC   UBALH2O   .185
+    VSGPLNC   UBALSTM   .013
+    VSGPLNC   UBALFUL   .0488
+    VSGPLNC   VCAPSGP   1.
+    VSGPLNB   MVOLLNB   1.
+    VSGPLNB   MVOLC3S   -.0277
+    VSGPLNB   MVOLNC4   -.0563
+    VSGPLNB   MVOLLSR   -.199
+    VSGPLNB   MVOLHSR   -.6873
+    VSGPLNB   MVOLIC4   -.017
+    VSGPLNB   UBALKWH   .495
+    VSGPLNB   UBALH2O   .209
+    VSGPLNB   UBALSTM   .013
+    VSGPLNB   UBALFUL   .0506
+    VSGPLNB   VCAPSGP   1.
+    VSGPLHG   MVOLLHG   1.0
+    VSGPLHG   MVOLC3S   -.175
+    VSGPLHG   MVOLNC4   -.27
+    VSGPLHG   MVOLLSR   -.028
+    VSGPLHG   MVOLIC4   -.455
+    VSGPLHG   UBALKWH   .495
+    VSGPLHG   UBALH2O   .209
+    VSGPLHG   UBALSTM   .013
+    VSGPLHG   UBALFUL   .0448
+    VSGPB95   MVOLB95   1.
+    VSGPB95   MVOLC3S   -.2836
+    VSGPB95   MVOLNC4   -.3285
+    VSGPB95   MVOLLSR   -.0241
+    VSGPB95   MVOLIC4   -.2502
+    VSGPB95   UBALKWH   .495
+    VSGPB95   UBALH2O   .209
+    VSGPB95   UBALSTM   .013
+    VSGPB95   UBALFUL   .0506
+    VSGPB90   MVOLB90   1.
+    VSGPB90   MVOLC3S   -.271
+    VSGPB90   MVOLNC4   -.3289
+    VSGPB90   MVOLLSR   -.0255
+    VSGPB90   MVOLIC4   -.2656
+    VSGPB90   UBALKWH   .495
+    VSGPB90   UBALH2O   .209
+    VSGPB90   UBALSTM   .013
+    VSGPB90   UBALFUL   .0506
+    VH2RHSR   MVOLHSR   1.
+    VH2RHSR   MVOLRFG   -1.
+    VH2RHSR   MSCFHYL   .0327
+    VH2RHSR   UBALKWH   .793
+    VH2RHSR   UBALH2O   .045
+    VH2RHSR   UBALFUL   .094
+    VH2RHSR   PROFIT    -.0176
+    VRFFRF1   MVOLRFG   1.0
+    VRFFRF1   MVOLR90   -1.0
+    VRFFRF2   MVOLRFG   1.0
+    VRFFRF2   MVOLR95   -1.0
+    VRFFHH1   MVOLR90   -1.0
+    VRFFHH1   MVOLHHG   1.0
+    VRFFHH2   MVOLR95   -1.0
+    VRFFHH2   MVOLHHG   1.0
+    VRFGR90   MVOLR90   1.0
+    VRFGR90   MVOLB90   -.0404
+    VRFGR90   MVOLF90   -0.8564
+    VRFGR90   MSCFHYL   -0.8239
+    VRFGR90   UBALKWH   .792
+    VRFGR90   UBALH2O   .297
+    VRFGR90   UBALSTM   0.0063
+    VRFGR90   UBALFUL   -0.156
+    VRFGR90   VCAPRFG   1.0
+    VRFGR90   PROFIT    -0.1512
+    VRFGR95   MVOLR95   1.0
+    VRFGR95   MVOLB95   -0.0588
+    VRFGR95   MVOLF95   -0.8145
+    VRFGR95   MSCFHYL   -.7689
+    VRFGR95   UBALKWH   1.03
+    VRFGR95   UBALH2O   .387
+    VRFGR95   UBALSTM   0.008
+    VRFGR95   UBALFUL   -.2112
+    VRFGR95   VCAPRFG   1.3
+    VRFGR95   PROFIT    -0.304
+    VHOLLCO   MVOLLCO   1.0
+    VHOLLCO   MVOLHHG   -.6627
+    VHOLLCO   MVOLLHG   -0.2414
+    VHOLLCO   MVOLHCD   -.2930
+    VHOLLCO   MSCFHYL   2.3
+    VHOLLCO   UBALFUL   -.2054
+    VHOLLCO   UBALH2O   0.826
+    VHOLLCO   UBALKWH   14.61
+    VHOLLCO   VCAPHOL   1.0
+    VHOLLCO   PROFIT    -0.2112
+    VHOLSRD   MVOLSRD   1.0
+    VHOLSRD   MVOLHHG   -.6627
+    VHOLSRD   MVOLLHG   -0.2414
+    VHOLSRD   MVOLHCD   -.2930
+    VHOLSRD   MSCFHYL   2.3
+    VHOLSRD   UBALFUL   -.2054
+    VHOLSRD   UBALH2O   0.826
+    VHOLSRD   UBALKWH   14.61
+    VHOLSRD   VCAPHOL   1.0
+    VHOLSRD   PROFIT    -0.2112
+    VHOLRCR   MVOLRCR   1.0
+    VHOLRCR   MVOLHHG   -.5875
+    VHOLRCR   MVOLLHG   -0.3321
+    VHOLRCR   MVOLHCD   -.3620
+    VHOLRCR   MSCFHYL   2.3
+    VHOLRCR   UBALFUL   -.2054
+    VHOLRCR   UBALH2O   0.826
+    VHOLRCR   UBALKWH   14.61
+    VHOLRCR   VCAPHOL   1.0
+    VHOLRCR   PROFIT    -0.2112
+    VHOLHVO   MVOLHVO   1.0
+    VHOLHVO   MVOLHHG   -.5875
+    VHOLHVO   MVOLLHG   -0.3321
+    VHOLHVO   MVOLHCD   -.3620
+    VHOLHVO   MSCFHYL   2.3
+    VHOLHVO   UBALFUL   -.2054
+    VHOLHVO   UBALH2O   0.826
+    VHOLHVO   UBALKWH   14.61
+    VHOLHVO   VCAPHVO   1.0
+    VHOLHVO   VCAPHOL   1.0
+    VHOLHVO   PROFIT    -0.2112
+    VCCUSRK   MVOLSRK   1.0
+    VCCUSRK   MVOLNC4   -0.0184
+    VCCUSRK   MVOLC3S   -0.0303
+    VCCUSRK   MVOLIC4   -0.0564
+    VCCUSRK   MVOLC3U   -0.0655
+    VCCUSRK   MVOLC4U   -0.0780
+    VCCUSRK   MVOLFCG   -0.4750
+    VCCUSRK   MVOLLCO   -0.3050
+    VCCUSRK   UBALSTM   -.0654
+    VCCUSRK   UBALFUL   -.2703
+    VCCUSRK   UBALH2O   .632
+    VCCUSRK   UBALKWH   .6807
+    VCCUSRK   VCAPCCU   1.
+    VCCUSRK   PROFIT    -.2112
+    VCCUSRD   MVOLSRD   1.
+    VCCUSRD   MVOLNC4   -.0184
+    VCCUSRD   MVOLC3S   -.0303
+    VCCUSRD   MVOLIC4   -.0564
+    VCCUSRD   MVOLC3U   -.0655
+    VCCUSRD   MVOLC4U   -.0780
+    VCCUSRD   MVOLFCG   -.4750
+    VCCUSRD   MVOLLCO   -.3050
+    VCCUSRD   UBALSTM   -.0654
+    VCCUSRD   UBALFUL   -.2703
+    VCCUSRD   UBALH2O   0.632
+    VCCUSRD   UBALKWH   .6807
+    VCCUSRD   VCAPCCU   1.
+    VCCUSRD   PROFIT    -.2112
+    VCCURCR   MVOLRCR   1.0
+    VCCURCR   MVOLNC4   -.0185
+    VCCURCR   MVOLC3S   -.0328
+    VCCURCR   MVOLIC4   -.0568
+    VCCURCR   MVOLC3U   -.0658
+    VCCURCR   MVOLC4U   -.0806
+    VCCURCR   MVOLFCG   -.4934
+    VCCURCR   MVOLLCO   -.2922
+    VCCURCR   MVOLSLR   -.0096
+    VCCURCR   UBALSTM   -.0654
+    VCCURCR   UBALFUL   -.2703
+    VCCURCR   UBALH2O   0.632
+    VCCURCR   UBALKWH   .6807
+    VCCURCR   VCAPCCU   1.
+    VCCURCR   PROFIT    -.2112
+    VCCUHVO   MVOLHVO   1.0
+    VCCUHVO   MVOLNC4   -.0185
+    VCCUHVO   MVOLC3S   -.0328
+    VCCUHVO   MVOLIC4   -.0568
+    VCCUHVO   MVOLC3U   -.0658
+    VCCUHVO   MVOLC4U   -.0806
+    VCCUHVO   MVOLFCG   -.4934
+    VCCUHVO   MVOLLCO   -.2922
+    VCCUHVO   MVOLSLR   -.0096
+    VCCUHVO   UBALSTM   -.0654
+    VCCUHVO   UBALFUL   -.2703
+    VCCUHVO   UBALH2O   0.632
+    VCCUHVO   UBALKWH   .6807
+    VCCUHVO   VCAPHVO   1.
+    VCCUHVO   VCAPCCU   1.
+    VCCUHVO   PROFIT    -.2112
+    VALKLA3   MVOLIC4   .7600
+    VALKLA3   MVOLC3U   .5714
+    VALKLA3   MVOLLA3   -1.0
+    VALKLA3   UBALSTM   .1869
+    VALKLA3   UBALFUL   .2796
+    VALKLA3   UBALH2O   2.241
+    VALKLA3   UBALKWH   2.766
+    VALKLA3   VCAPALK   1.0
+    VALKLA3   PROFIT    -.512
+    VALKLA4   MVOLIC4   .6571
+    VALKLA4   MVOLC4U   .5714
+    VALKLA4   MVOLC3S   -.0571
+    VALKLA4   MVOLNC4   -.0114
+    VALKLA4   MVOLLA4   -1.0
+    VALKLA4   UBALSTM   .1724
+    VALKLA4   UBALFUL   .2579
+    VALKLA4   UBALH2O   2.067
+    VALKLA4   UBALKWH   2.552
+    VALKLA4   VCAPALK   1.0
+    VALKLA4   PROFIT    -.472
+    VALKIC4   MVOLIC4   1.0
+    VALKIC4   MVOLNC4   -1.0
+    VALKC3U   MVOLC3U   1.0
+    VALKC3U   MVOLC3S   -1.0
+    VALKC4U   MVOLC4U   1.0
+    VALKC4U   MVOLNC4   -1.0
+    UTILC3S   MVOLC3S   1.
+    UTILC3S   UBALFUL   -3.814
+    UTILNC4   MVOLNC4   1.
+    UTILNC4   UBALFUL   -4.316
+    UTILIC4   MVOLIC4   1.
+    UTILIC4   UBALFUL   -4.153
+    UTILC3U   MVOLC3U   1.
+    UTILC3U   UBALFUL   -3.808
+    UTILC4U   MVOLC4U   1.
+    UTILC4U   UBALFUL   -4.44
+    UTILHYL   MSCFHYL   1.
+    UTILHYL   UBALFUL   -.305
+    UTILSTM   UBALSTM   -1.
+    UTILSTM   UBALFUL   1.42
+    UTILSTM   PROFIT    -.16
+    PURCPC4   MVOLIC4   -.5
+    PURCPC4   MVOLNC4   -.5
+    PURCPC4   PROFIT    -12.
+    PURCH2O   UBALH2O   -1.
+    PURCH2O   PROFIT    -.0528
+    PURCKWH   UBALKWH   -1.
+    PURCKWH   PROFIT    -.04
+    PURCFUL   UBALFUL   -1.
+    PURCFUL   PROFIT    -1.6
+    PURCFLR   UBALFUL   1.
+    BLPGC3S   MVOLC3S   1.0
+    BLPGC3S   EVOLLPG   -1.0
+    BLPGNC4   MVOLNC4   1.0
+    BLPGNC4   EVOLLPG   -1.0
+    SELLLPG   EVOLLPG   1.0
+    SELLLPG   PROFIT    11.0
+    BUP4LSR   MVOLLSR   1.0
+    BUP4LSR   EVOLJP4   -1.0
+    BUP4LSR   XRVXJP4   14.0
+    BUP4LSR   XRVNJP4   -14.0
+    BUP4HSR   MVOLHSR   1.0
+    BUP4HSR   EVOLJP4   -1.0
+    BUP4HSR   XRVXJP4   0.8
+    BUP4HSR   XRVNJP4   -0.8
+    SELLJP4   EVOLJP4   1.0
+    SELLJP4   XRVXJP4   -3.0
+    SELLJP4   XRVNJP4   2.0
+    SELLJP4   PROFIT    16.8
+    BDSLSRK   MVOLSRK   1.0
+    BDSLSRK   EVOLDSL   -1.0
+    BDSLSRD   MVOLSRD   1.0
+    BDSLSRD   EVOLDSL   -1.0
+    SELLDSL   EVOLDSL   1.0
+    SELLDSL   PROFIT    14.4
+    BPRELSR   MVOLLSR   1.
+    BPRELSR   XLPRPRE   -7.95
+    BPRELSR   XHPRPRE   -8.70
+    BPRELSR   XTELPRE   -3.00
+    BPRELSR   XRVPPRE   14.00
+    BPRELSR   X200PRE   1.
+    BPRELSR   X230PRE   -1.
+    BPRELSR   EVOLPRE   -1.
+    BPREHCD   MVOLHCD   1.0
+    BPREHCD   XLPRPRE   -8.84
+    BPREHCD   XHPRPRE   -9.45
+    BPREHCD   XTELPRE   -3.00
+    BPREHCD   XRVPPRE   12.00
+    BPREHCD   X200PRE   1.
+    BPREHCD   X230PRE   -1.
+    BPREHCD   EVOLPRE   -1.
+    BPREF95   MVOLF95   1.0
+    BPREF95   XLPRPRE   -9.43
+    BPREF95   XHPRPRE   -9.57
+    BPREF95   XTELPRE   -3.
+    BPREF95   XRVPPRE   3.5
+    BPREF95   X200PRE   .233
+    BPREF95   X230PRE   -.358
+    BPREF95   EVOLPRE   -1.
+    BPREF90   MVOLF90   1.0
+    BPREF90   XLPRPRE   -9.03
+    BPREF90   XHPRPRE   -9.32
+    BPREF90   XTELPRE   -3.0
+    BPREF90   XRVPPRE   3.5
+    BPREF90   X200PRE   .205
+    BPREF90   X230PRE   -.333
+    BPREF90   EVOLPRE   -1.
+    BPREFCG   MVOLFCG   1.0
+    BPREFCG   XLPRPRE   -9.23
+    BPREFCG   XHPRPRE   -9.22
+    BPREFCG   XTELPRE   -3.
+    BPREFCG   XRVPPRE   6.
+    BPREFCG   X200PRE   .381
+    BPREFCG   X230PRE   -.509
+    BPREFCG   EVOLPRE   -1.
+    BPRELA3   MVOLLA3   1.0
+    BPRELA3   XLPRPRE   -9.4
+    BPRELA3   XHPRPRE   -9.85
+    BPRELA3   XTELPRE   -3.0
+    BPRELA3   XRVPPRE   2.5
+    BPRELA3   X200PRE   0.39
+    BPRELA3   X230PRE   -0.77
+    BPRELA3   EVOLPRE   -1.0
+    BPRELA4   MVOLLA4   1.0
+    BPRELA4   XLPRPRE   -9.74
+    BPRELA4   XHPRPRE   -10.1
+    BPRELA4   XTELPRE   -3.0
+    BPRELA4   XRVPPRE   3.3
+    BPRELA4   X200PRE   0.233
+    BPRELA4   X230PRE   -0.58
+    BPRELA4   EVOLPRE   -1.0
+    BPRENC4   MVOLNC4   1.0
+    BPRENC4   XLPRPRE   -9.74
+    BPRENC4   XHPRPRE   -9.9
+    BPRENC4   XTELPRE   -3.0
+    BPRENC4   XRVPPRE   66.0
+    BPRENC4   X200PRE   1.0
+    BPRENC4   X230PRE   -1.0
+    BPRENC4   EVOLPRE   -1.0
+    BPRETEL   XLPRPRE   -0.493
+    BPRETEL   XHPRPRE   -0.165
+    BPRETEL   XTELPRE   1.0
+    BPRETEL   PROFIT    -0.3696
+    SELLPRE   XLPRPRE   10.03
+    SELLPRE   XHPRPRE   10.03
+    SELLPRE   XRVPPRE   -9.5
+    SELLPRE   X200PRE   -0.5
+    SELLPRE   X230PRE   0.5
+    SELLPRE   XPSCPRE   0.64
+    SELLPRE   XRSCREG   0.35
+    SELLPRE   EVOLPRE   1.0
+    SELLPRE   PROFIT    21.44
+    BINTLSR   MVOLLSR   1.0
+    BINTLSR   XLPRINT   -7.98
+    BINTLSR   XHPRINT   -8.58
+    BINTLSR   XTELINT   -3.0
+    BINTLSR   XRVPINT   14.0
+    BINTLSR   X200INT   1.0
+    BINTLSR   X230INT   -1.0
+    BINTLSR   EVOLINT   -1.0
+    BINTHCD   MVOLHCD   1.
+    BINTHCD   XLPRINT   -8.87
+    BINTHCD   XHPRINT   -9.33
+    BINTHCD   XTELINT   -3.0
+    BINTHCD   XRVPINT   12.0
+    BINTHCD   X200INT   1.0
+    BINTHCD   X230INT   -1.
+    BINTHCD   EVOLINT   -1.0
+    BINTF95   MVOLF95   1.
+    BINTF95   XLPRINT   -9.46
+    BINTF95   XHPRINT   -9.45
+    BINTF95   XTELINT   -3.0
+    BINTF95   XRVPINT   3.5
+    BINTF95   X200INT   .233
+    BINTF95   X230INT   -.358
+    BINTF95   EVOLINT   -1.0
+    BINTF90   MVOLF90   1.
+    BINTF90   XLPRINT   -9.06
+    BINTF90   XHPRINT   -9.20
+    BINTF90   XTELINT   -3.0
+    BINTF90   XRVPINT   3.5
+    BINTF90   X200INT   .205
+    BINTF90   X230INT   -.333
+    BINTF90   EVOLINT   -1.0
+    BINTFCG   MVOLFCG   1.
+    BINTFCG   XLPRINT   -9.26
+    BINTFCG   XHPRINT   -9.13
+    BINTFCG   XTELINT   -3.0
+    BINTFCG   XRVPINT   6.
+    BINTFCG   X200INT   .318
+    BINTFCG   X230INT   -.509
+    BINTFCG   EVOLINT   -1.0
+    BINTNC4   MVOLNC4   1.
+    BINTNC4   XLPRINT   -9.77
+    BINTNC4   XHPRINT   -9.78
+    BINTNC4   XTELINT   -3.0
+    BINTNC4   XRVPINT   66.
+    BINTNC4   X200INT   1.0
+    BINTNC4   X230INT   -1.
+    BINTNC4   EVOLINT   -1.0
+    BINTTEL   XLPRINT   -.435
+    BINTTEL   XHPRINT   -.208
+    BINTTEL   XTELINT   1.
+    BINTTEL   PROFIT    -.3696
+    SELLINT   XLPRINT   9.65
+    SELLINT   XHPRINT   9.65
+    SELLINT   XRVPINT   -9.5
+    SELLINT   X200INT   -0.5
+    SELLINT   X230INT   0.5
+    SELLINT   XPSCPRE   -.36
+    SELLINT   XRSCREG   0.35
+    SELLINT   EVOLINT   1.0
+    SELLINT   PROFIT    20.32
+    BREGLSR   MVOLLSR   1.0
+    BREGLSR   XLPRREG   -7.99
+    BREGLSR   XHPRREG   -8.59
+    BREGLSR   XTELREG   -3.0
+    BREGLSR   XRVPREG   14.0
+    BREGLSR   X200REG   1.0
+    BREGLSR   X230REG   -1.0
+    BREGLSR   EVOLREG   -1.0
+    BREGHCD   MVOLHCD   1.0
+    BREGHCD   XLPRREG   -8.88
+    BREGHCD   XHPRREG   -9.34
+    BREGHCD   XTELREG   -3.0
+    BREGHCD   XRVPREG   12.0
+    BREGHCD   X200REG   1.0
+    BREGHCD   X230REG   -1.0
+    BREGHCD   EVOLREG   -1.0
+    BREGF95   MVOLF95   1.0
+    BREGF95   XLPRREG   -9.47
+    BREGF95   XHPRREG   -9.46
+    BREGF95   XTELREG   -3.0
+    BREGF95   XRVPREG   3.5
+    BREGF95   X200REG   .233
+    BREGF95   X230REG   -0.358
+    BREGF95   EVOLREG   -1.0
+    BREGF90   MVOLF90   1.0
+    BREGF90   XLPRREG   -9.07
+    BREGF90   XHPRREG   -9.21
+    BREGF90   XTELREG   -3.0
+    BREGF90   XRVPREG   3.5
+    BREGF90   X200REG   .205
+    BREGF90   X230REG   -0.333
+    BREGF90   EVOLREG   -1.0
+    BREGFCG   MVOLFCG   1.0
+    BREGFCG   XLPRREG   -9.27
+    BREGFCG   XHPRREG   -9.14
+    BREGFCG   XTELREG   -3.0
+    BREGFCG   XRVPREG   6.0
+    BREGFCG   X200REG   0.318
+    BREGFCG   X230REG   -0.509
+    BREGFCG   EVOLREG   -1.0
+    BREGNC4   MVOLNC4   1.0
+    BREGNC4   XLPRREG   -9.78
+    BREGNC4   XHPRREG   -9.79
+    BREGNC4   XTELREG   -3.0
+    BREGNC4   XRVPREG   66.0
+    BREGNC4   X200REG   1.0
+    BREGNC4   X230REG   -1.0
+    BREGNC4   EVOLREG   -1.0
+    BREGTEL   XLPRREG   -0.426
+    BREGTEL   XHPRREG   -.204
+    BREGTEL   XTELREG   1.0
+    BREGTEL   PROFIT    -0.3696
+    SELLREG   XLPRREG   9.05
+    SELLREG   XHPRREG   9.05
+    SELLREG   XRVPREG   -9.5
+    SELLREG   X200REG   -0.5
+    SELLREG   X230REG   0.5
+    SELLREG   XPSCPRE   -0.36
+    SELLREG   XRSCREG   -0.65
+    SELLREG   EVOLREG   1.0
+    SELLREG   PROFIT    18.04
+    BRSDVBB   MVOLVBB   1.0
+    BRSDVBB   EVOLRSD   -1.0
+    BRSDVBB   XVISRSD   10.1
+    BRSDVBC   MVOLVBC   1.0
+    BRSDVBC   EVOLRSD   -1.0
+    BRSDVBC   XVISRSD   12.63
+    BRSDRCR   MVOLRCR   1.0
+    BRSDRCR   EVOLRSD   -1.0
+    BRSDRCR   XVISRSD   6.9
+    BRSDHVO   MVOLHVO   1.0
+    BRSDHVO   EVOLRSD   -1.0
+    BRSDHVO   XVISRSD   8.05
+    BRSDHVO   VCAPHVO   1.0
+    BRSDSLR   MVOLSLR   1.0
+    BRSDSLR   EVOLRSD   -1.0
+    BRSDSLR   XVISRSD   8.05
+    BRSDLCO   MVOLLCO   1.0
+    BRSDLCO   EVOLRSD   -1.0
+    BRSDLCO   XVISRSD   4.4
+    SELLRSD   EVOLRSD   1.0
+    SELLRSD   XVISRSD   -10.1
+    SELLRSD   PROFIT    8.00
+RHS
+    LIMITMAX  MVOLBOL   26.316
+    LIMITMAX  MVOLCOL   21.052
+    LIMITMAX  VCAPSGP   23.25
+    LIMITMAX  VCAPHVO   5.25
+    LIMITMAX  VCAPRFG   13.455
+    LIMITMAX  VCAPHOL   3.87
+    LIMITMAX  VCAPCCU   7.26
+    LIMITMAX  VCAPALK   10.
+ENDATA
Index: deps/glpk/examples/mvcp.mod
===================================================================
--- deps/glpk/examples/mvcp.mod	(revision 9)
+++ deps/glpk/examples/mvcp.mod	(revision 9)
@@ -0,0 +1,43 @@
+/* MVCP, Minimum Vertex Cover Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Minimum Vertex Cover Problem in a network G = (V, E), where V
+   is a set of nodes, E is a set of arcs, is to find a subset V' within
+   V such that each edge (i,j) in E has at least one its endpoint in V'
+   and which minimizes the sum of node weights w(i) over V'.
+
+   Reference:
+   Garey, M.R., and Johnson, D.S. (1979), Computers and Intractability:
+   A guide to the theory of NP-completeness [Graph Theory, Covering and
+   Partitioning, Minimum Vertex Cover, GT1]. */
+
+set E, dimen 2;
+/* set of edges */
+
+set V := (setof{(i,j) in E} i) union (setof{(i,j) in E} j);
+/* set of nodes */
+
+param w{i in V}, >= 0, default 1;
+/* w[i] is weight of vertex i */
+
+var x{i in V}, binary;
+/* x[i] = 1 means that node i is included into V' */
+
+s.t. cov{(i,j) in E}: x[i] + x[j] >= 1;
+/* each edge (i,j) must have node i or j (or both) in V' */
+
+minimize z: sum{i in V} w[i] * x[i];
+/* we need to minimize the sum of node weights over V' */
+
+data;
+
+/* These data correspond to an example from [Papadimitriou]. */
+
+/* Optimal solution is 6 (greedy heuristic gives 13) */
+
+set E := a1 b1, b1 c1, a1 b2, b2 c2, a2 b3, b3 c3, a2 b4, b4 c4, a3 b5,
+         b5 c5, a3 b6, b6 c6, a4 b1, a4 b2, a4 b3, a5 b4, a5 b5, a5 b6,
+         a6 b1, a6 b2, a6 b3, a6 b4, a7 b2, a7 b3, a7 b4, a7 b5, a7 b6;
+
+end;
Index: deps/glpk/examples/netgen.c
===================================================================
--- deps/glpk/examples/netgen.c	(revision 9)
+++ deps/glpk/examples/netgen.c	(revision 9)
@@ -0,0 +1,141 @@
+/* netgen.c */
+
+/* This main program generates 50 original NETGEN instances of the
+   minimum cost flow problem and writes them in DIMACS format to the
+   current directory. */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+static int parm[50][15] =
+{    {13502460, 101,
+      5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
+   },{4281922, 102,
+      5000, 2500, 2500, 25000, 1, 100, 2500000, 0, 0, 0, 100, 1, 1000,
+   },{44820113, 103,
+      5000, 2500, 2500, 25000, 1, 100, 6250000, 0, 0, 0, 100, 1, 1000,
+   },{13450451, 104,
+      5000, 2500, 2500, 25000, -100, -1, 250000, 0, 0, 0, 100, 1, 1000,
+   },{14719436, 105,
+      5000, 2500, 2500, 25000, 101, 200, 250000, 0, 0, 0, 100, 1, 1000,
+   },{17365786, 106,
+      5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 100, 1, 1000,
+   },{19540113, 107,
+      5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 100, 1, 1000,
+   },{19560313, 108,
+      5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 100, 1, 1000,
+   },{2403509, 109,
+      5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 100, 1, 1000,
+   },{92480414, 110,
+      5000, 2500, 2500, 12500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
+   },{4230140, 111,
+      5000, 2500, 2500, 37500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
+   },{10032490, 112,
+      5000, 2500, 2500, 50000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
+   },{17307474, 113,
+      5000, 2500, 2500, 75000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
+   },{4925114, 114,
+      5000, 500, 4500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
+   },{19842704, 115,
+      5000, 1500, 3500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000,
+   },{88392060, 116,
+      5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 0, 1, 1000,
+   },{12904407, 117,
+      5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 0, 1, 1000,
+   },{11811811, 118,
+      5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 0, 1, 1000,
+   },{90023593, 119,
+      5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 0, 1, 1000,
+   },{93028922, 120,
+      5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 0, 1, 1000,
+   },{72707401, 121,
+      5000, 50, 50, 25000, 1, 100, 250000, 50, 50, 0, 100, 1, 1000,
+   },{93040771, 122,
+      5000, 250, 250, 25000, 1, 100, 250000, 250, 250, 0, 100, 1, 1000,
+   },{70220611, 123,
+      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{52774811, 124,
+      5000, 1000, 1000, 25000, 1, 100, 250000, 1000, 1000, 0, 100, 1,
+      1000,
+   },{22492311, 125,
+      5000, 1500, 1500, 25000, 1, 100, 250000, 1500, 1500, 0, 100, 1,
+      1000,
+   },{35269337, 126,
+      5000, 500, 500, 12500, 1, 100, 125000, 500, 500, 0, 100, 1, 1000,
+   },{30140502, 127,
+      5000, 500, 500, 37500, 1, 100, 375000, 500, 500, 0, 100, 1, 1000,
+   },{49205455, 128,
+      5000, 500, 500, 50000, 1, 100, 500000, 500, 500, 0, 100, 1, 1000,
+   },{42958341, 129,
+      5000, 500, 500, 75000, 1, 100, 750000, 500, 500, 0, 100, 1, 1000,
+   },{25440925, 130,
+      5000, 500, 500, 12500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{75294924, 131,
+      5000, 500, 500, 37500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{4463965, 132,
+      5000, 500, 500, 50000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{13390427, 133,
+      5000, 500, 500, 75000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{95250971, 134,
+      1000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{54830522, 135,
+      2500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{520593, 136,
+      7500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{52900925, 137,
+      10000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000,
+   },{22603395, 138,
+      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 50,
+   },{55253099, 139,
+      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 250,
+   },{75357001, 140,
+      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 500,
+   },{10072459, 141,
+      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 2500,
+   },{55728492, 142,
+      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 5000,
+   },{593043, 143,
+      5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 0, 1, 1000,
+   },{94236572, 144,
+      5000, 500, 500, 25000, 1, 10, 250000, 500, 500, 0, 100, 1, 1000,
+   },{94882955, 145,
+      5000, 500, 500, 25000, 1, 1000, 250000, 500, 500, 0, 100, 1, 1000,
+   },{48489922, 146,
+      5000, 500, 500, 25000, 1, 10000, 250000, 500, 500, 0, 100, 1,
+      1000,
+   },{75578374, 147,
+      5000, 500, 500, 25000, -100, -1, 250000, 500, 500, 0, 100, 1,
+      1000,
+   },{44821152, 148,
+      5000, 500, 500, 25000, -50, 49, 250000, 500, 500, 0, 100, 1, 1000,
+   },{45224103, 149,
+      5000, 500, 500, 25000, 101, 200, 250000, 500, 500, 0, 100, 1,
+      1000,
+   },{63491741, 150,
+      5000, 500, 500, 25000, 1001, 1100, 250000, 500, 500, 0, 100, 1,
+      1000,
+   }
+};
+
+typedef struct { double rhs; } v_data;
+typedef struct { double cap, cost; } a_data;
+
+int main(void)
+{     glp_graph *G;
+      int k;
+      char fname[100+1];
+      G = glp_create_graph(sizeof(v_data), sizeof(a_data));
+      for (k = 1; k <= 50; k++)
+      {  sprintf(fname, "netgn%03d.min", parm[k-1][1]);
+         glp_netgen(G, offsetof(v_data, rhs), offsetof(a_data, cap),
+            offsetof(a_data, cost), &parm[k-1][-1]);
+         glp_write_mincost(G, offsetof(v_data, rhs), -1,
+            offsetof(a_data, cap), offsetof(a_data, cost), fname);
+      }
+      glp_delete_graph(G);
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/examples/numbrix.mod
===================================================================
--- deps/glpk/examples/numbrix.mod	(revision 9)
+++ deps/glpk/examples/numbrix.mod	(revision 9)
@@ -0,0 +1,84 @@
+/* Numbrix, Number Placement Puzzle */
+
+/* Written in GNU MathProg by Robert Wood <rwood@targus.com>  */
+
+/* Numbrix is a logic-based number-placement puzzle.[1]
+ * The objective is to fill the grid so that each cell contains
+ * digits in sequential order taking a horizontal or vertical
+ * path; diagonal paths are not allowed. The puzzle setter
+ * provides a grid often with the outer most cells completed.
+ *
+ * Completed Numbrix puzzles are usually a square of numbers
+ * in order from 1 to 64 (8x8 grid) or from 1 to 81 (9x9 grid),
+ * following a continuous path in sequence.
+ *
+ * The modern puzzle was invented by Marilyn vos Savant in 2008
+ * and published by Parade Magazine under the name "Numbrix",
+ * near her weekly Ask Marilyn article.
+ *
+ *    http://en.wikipedia.org/wiki/Numbrix  */
+
+set I := {1..9};
+set J := {1..9};
+set VALS := {1..81};
+
+param givens{I, J}, integer, >= 0, <= 81, default 0;
+/* the "givens" */
+
+param neighbors{i in I,j in J, i2 in I, j2 in J} , binary :=
+(if abs(i - i2) + abs(j -j2) == 1 then
+     1
+ else
+     0
+);
+/*  defines which spots are the boards are neighbors */
+
+var x{i in I, j in J, k in VALS}, binary;
+/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
+
+s.t. fa{i in I, j in J, k in VALS: givens[i,j] != 0}:
+     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
+/* assign pre-defined numbers using the "givens" */
+
+s.t. fb{i in I, j in J}: sum{k in VALS} x[i,j,k] = 1;
+/* each cell must be assigned exactly one number */
+
+s.t. singleNum {k in VALS}:  sum{i in I, j in J} x[i,j,k] = 1;
+/*  a value can only occur once */
+
+s.t. neighborContraint {i in I, j in J, k in 1..80}:
+        x[i,j,k] <= sum{i2 in I, j2 in J} x[i2,j2,k+1] * neighbors[i,j,i2,j2];
+/* each cell must have a neighbor with the next higher value */
+
+
+/* there is no need for an objective function here */
+
+
+solve;
+
+for {i in I}
+{  for {0..0: i = 1 or i = 4 or i = 7}
+      printf " +----------+----------+----------+\n";
+   for {j in J}
+   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
+      printf " %2d", sum{k in VALS} x[i,j,k] * k;
+      for {0..0: j = 9} printf(" |\n");
+   }
+   for {0..0: i = 9}
+      printf " +----------+----------+----------+\n";
+}
+
+data;
+
+param givens : 1 2 3 4 5 6 7 8 9 :=
+           1   . . . . . . . . .
+           2   . 11 12 15 18 21 62 61 .
+           3   .  6 . . . . . 60 .
+           4   . 33 . . . . . 57 .
+           5   . 32 . . . . . 56 .
+           6   . 37 . . . . . 73 .
+           7   . 38 . . . . . 72 .
+           8   . 43 44 47 48 51 76 77 .
+           9   . . . . . . . . . ;
+
+end;
Index: deps/glpk/examples/pbn/9dom.dat
===================================================================
--- deps/glpk/examples/pbn/9dom.dat	(revision 9)
+++ deps/glpk/examples/pbn/9dom.dat	(revision 9)
@@ -0,0 +1,65 @@
+/* 9dom.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #8098 from <www.webpbn.com>.
+*  Copyright (C) 2010 by Josh Greifer. Used by permission.
+*
+*  Domino Logic III (Abstract pattern)
+*
+*  created by Josh Greifer
+*  Apr 5, 2010
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 19;
+
+param n := 19;
+
+param row : 1  2  :=
+      1     3  .
+      2     1  .
+      3     3  1
+      4     1  .
+      5     3  1
+      6     1  .
+      7     3  1
+      8     1  .
+      9     3  1
+      10    1  .
+      11    3  1
+      12    1  .
+      13    3  1
+      14    1  .
+      15    3  1
+      16    1  .
+      17    3  1
+      18    1  .
+      19    1  .
+;
+
+param col : 1  2  :=
+      1     1  .
+      2     1  .
+      3     1  3
+      4     1  .
+      5     1  3
+      6     1  .
+      7     1  3
+      8     1  .
+      9     1  3
+      10    1  .
+      11    1  3
+      12    1  .
+      13    1  3
+      14    1  .
+      15    1  3
+      16    1  .
+      17    1  3
+      18    1  .
+      19    3  .
+;
+
+end;
Index: deps/glpk/examples/pbn/README
===================================================================
--- deps/glpk/examples/pbn/README	(revision 9)
+++ deps/glpk/examples/pbn/README	(revision 9)
@@ -0,0 +1,6 @@
+This subdirectory contains examples, which illustrate how to use
+GLPK and the GNU MathProg modeling language for practical solving the
+paint-by-numbers puzzle.
+
+For details please see the document "Solving Paint-By-Numbers Puzzles
+with GLPK" included in this subdirectory (file pbn.pdf).
Index: deps/glpk/examples/pbn/bucks.dat
===================================================================
--- deps/glpk/examples/pbn/bucks.dat	(revision 9)
+++ deps/glpk/examples/pbn/bucks.dat	(revision 9)
@@ -0,0 +1,77 @@
+/* bucks.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #27 from <www.webpbn.com>.
+*  Copyright (C) 2004 by Jan Wolter. Used by permission.
+*
+*  Party at the Right [Political]
+*
+*  created by Jan Wolter
+*  Apr 6, 2004
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 23;
+
+param n := 27;
+
+param row : 1  2  3  4  5  6  7  8  :=
+      1     11 .  .  .  .  .  .  .
+      2     17 .  .  .  .  .  .  .
+      3     3  5  5  3  .  .  .  .
+      4     2  2  2  1  .  .  .  .
+      5     2  1  3  1  3  1  4  .
+      6     3  3  3  3  .  .  .  .
+      7     5  1  3  1  3  1  3  .
+      8     3  2  2  4  .  .  .  .
+      9     5  5  5  5  .  .  .  .
+      10    23 .  .  .  .  .  .  .
+      11    .  .  .  .  .  .  .  .
+      12    23 .  .  .  .  .  .  .
+      13    1  1  .  .  .  .  .  .
+      14    1  1  .  .  .  .  .  .
+      15    1  2  1  .  .  .  .  .
+      16    1  1  1  1  .  .  .  .
+      17    1  1  1  1  .  .  .  .
+      18    1  10 1  2  1  .  .  .
+      19    1  1  1  1  1  1  3  .
+      20    1  1  1  1  1  1  1  1
+      21    1  1  1  1  1  1  1  .
+      22    1  1  1  1  2  2  .  .
+      23    5  5  3  .  .  .  .  .
+;
+
+param col : 1  2  3  4  5  6  :=
+      1     4  12 .  .  .  .
+      2     6  1  1  .  .  .
+      3     8  1  1  .  .  .
+      4     3  2  2  1  1  .
+      5     2  1  1  2  1  6
+      6     1  1  1  1  .  .
+      7     3  1  1  2  1  1
+      8     3  2  3  1  1  .
+      9     10 1  1  .  .  .
+      10    4  2  2  1  1  .
+      11    3  1  1  2  1  1
+      12    2  1  1  1  .  .
+      13    3  1  1  2  1  1
+      14    3  2  3  1  6  .
+      15    10 1  1  .  .  .
+      16    4  2  2  1  1  .
+      17    3  1  1  2  1  1
+      18    1  1  1  9  .  .
+      19    2  1  1  2  1  1
+      20    2  2  3  1  3  .
+      21    8  1  5  .  .  .
+      22    6  1  1  .  .  .
+      23    4  9  1  .  .  .
+      24    1  1  .  .  .  .
+      25    2  1  .  .  .  .
+      26    1  1  .  .  .  .
+      27    4  .  .  .  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/cat.dat
===================================================================
--- deps/glpk/examples/pbn/cat.dat	(revision 9)
+++ deps/glpk/examples/pbn/cat.dat	(revision 9)
@@ -0,0 +1,67 @@
+/* cat.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #6 from <www.webpbn.com>.
+*  Copyright (C) 2004 by Jan Wolter. Used by permission.
+*
+*  Scardy Cat
+*
+*  created by Jan Wolter
+*  Mar 24, 2004
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 20;
+
+param n := 20;
+
+param row : 1  2  3  4  :=
+      1     2  .  .  .
+      2     2  .  .  .
+      3     1  .  .  .
+      4     1  .  .  .
+      5     1  3  .  .
+      6     2  5  .  .
+      7     1  7  1  1
+      8     1  8  2  2
+      9     1  9  5  .
+      10    2  16 .  .
+      11    1  17 .  .
+      12    7  11 .  .
+      13    5  5  3  .
+      14    5  4  .  .
+      15    3  3  .  .
+      16    2  2  .  .
+      17    2  1  .  .
+      18    1  1  .  .
+      19    2  2  .  .
+      20    2  2  .  .
+;
+
+param col : 1  2  3  :=
+      1     5  .  .
+      2     5  3  .
+      3     2  3  4
+      4     1  7  2
+      5     8  .  .
+      6     9  .  .
+      7     9  .  .
+      8     8  .  .
+      9     7  .  .
+      10    8  .  .
+      11    9  .  .
+      12    10 .  .
+      13    13 .  .
+      14    6  2  .
+      15    4  .  .
+      16    6  .  .
+      17    6  .  .
+      18    5  .  .
+      19    6  .  .
+      20    6  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/dancer.dat
===================================================================
--- deps/glpk/examples/pbn/dancer.dat	(revision 9)
+++ deps/glpk/examples/pbn/dancer.dat	(revision 9)
@@ -0,0 +1,42 @@
+/* dancer.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #1 from <www.webpbn.com>.
+*  Copyright (C) 2004 by Jan Wolter. Used by permission.
+*
+*  Demo Puzzle from Front Page
+*
+*  created by Jan Wolter
+*  Mar 24, 2004
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 10;
+
+param n := 5;
+
+param row : 1  2  3  :=
+      1     2  .  .
+      2     2  1  .
+      3     1  1  .
+      4     3  .  .
+      5     1  1  .
+      6     1  1  .
+      7     2  .  .
+      8     1  1  .
+      9     1  2  .
+      10    2  .  .
+;
+
+param col : 1  2  3  :=
+      1     2  1  .
+      2     2  1  3
+      3     7  .  .
+      4     1  3  .
+      5     2  1  .
+;
+
+end;
Index: deps/glpk/examples/pbn/dragon.dat
===================================================================
--- deps/glpk/examples/pbn/dragon.dat	(revision 9)
+++ deps/glpk/examples/pbn/dragon.dat	(revision 9)
@@ -0,0 +1,61 @@
+/* dragon.dat */
+
+/***********************************************************************
+*  Hard 20x20 paint-by-numbers puzzle designed by Won Yoon Jo
+*  from the article "Painting by Numbers" by Robert A. Bosch (2000),
+*  <http://www.oberlin.edu/~math/faculty/bosch/pbn-page.html>.
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 20;
+
+param n := 20;
+
+param row :    1  2  3  4  5 :=
+          1    7  1  .  .  .
+          2    1  1  2  .  .
+          3    2  1  2  .  .
+          4    1  2  2  .  .
+          5    4  2  3  .  .
+          6    3  1  4  .  .
+          7    3  1  3  .  .
+          8    2  1  4  .  .
+          9    2  9  .  .  .
+          10   2  1  5  .  .
+          11   2  7  .  .  .
+          12   14 .  .  .  .
+          13   8  2  .  .  .
+          14   6  2  2  .  .
+          15   2  8  1  3  .
+          16   1  5  5  2  .
+          17   1  3  2  4  1
+          18   3  1  2  4  1
+          19   1  1  3  1  3
+          20   2  1  1  2  . ;
+
+param col :    1  2  3  4  5 :=
+          1    1  1  1  2  .
+          2    3  1  2  1  1
+          3    1  4  2  1  1
+          4    1  3  2  4  .
+          5    1  4  6  1  .
+          6    1  11 1  .  .
+          7    5  1  6  2  .
+          8    14 .  .  .  .
+          9    7  2  .  .  .
+          10   7  2  .  .  .
+          11   6  1  1  .  .
+          12   9  2  .  .  .
+          13   3  1  1  1  .
+          14   3  1  3  .  .
+          15   2  1  3  .  .
+          16   2  1  5  .  .
+          17   3  2  2  .  .
+          18   3  3  2  .  .
+          19   2  3  2  .  .
+          20   2  6  .  .  . ;
+
+end;
Index: deps/glpk/examples/pbn/edge.dat
===================================================================
--- deps/glpk/examples/pbn/edge.dat	(revision 9)
+++ deps/glpk/examples/pbn/edge.dat	(revision 9)
@@ -0,0 +1,48 @@
+/* edge.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #23 from <www.webpbn.com>.
+*  Copyright (C) 2004 by Jan Wolter. Used by permission.
+*
+*  Nonrepresentational Test Pattern
+*
+*  created by Jan Wolter
+*  Apr 5, 2004
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 11;
+
+param n := 10;
+
+param row : 1  :=
+      1     1
+      2     3
+      3     1
+      4     2
+      5     1
+      6     3
+      7     3
+      8     1
+      9     2
+      10    2
+      11    4
+;
+
+param col : 1  2  :=
+      1     1  .
+      2     3  .
+      3     1  .
+      4     2  2
+      5     2  .
+      6     4  .
+      7     1  .
+      8     3  .
+      9     3  .
+      10    1  .
+;
+
+end;
Index: deps/glpk/examples/pbn/forever.dat
===================================================================
--- deps/glpk/examples/pbn/forever.dat	(revision 9)
+++ deps/glpk/examples/pbn/forever.dat	(revision 9)
@@ -0,0 +1,77 @@
+/* forever.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #6574 from <www.webpbn.com>.
+*  Copyright (C) 2009 by Gator. Used by permission.
+*
+*  Lasts Forever
+*
+*  created by Gator
+*  Aug 24, 2009
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 25;
+
+param n := 25;
+
+param row : 1  2  3  4  5  6  7  8  :=
+      1     1  2  2  2  2  2  1  .
+      2     1  2  2  2  2  2  1  1
+      3     1  1  .  .  .  .  .  .
+      4     1  1  .  .  .  .  .  .
+      5     1  3  1  .  .  .  .  .
+      6     1  13 1  .  .  .  .  .
+      7     1  13 1  .  .  .  .  .
+      8     1  13 1  .  .  .  .  .
+      9     1  4  4  1  .  .  .  .
+      10    1  4  3  4  1  .  .  .
+      11    1  4  5  4  1  .  .  .
+      12    1  7  1  .  .  .  .  .
+      13    1  7  1  .  .  .  .  .
+      14    1  7  1  .  .  .  .  .
+      15    1  7  1  .  .  .  .  .
+      16    1  1  5  1  .  .  .  .
+      17    1  2  6  1  .  .  .  .
+      18    1  4  6  1  .  .  .  .
+      19    1  6  6  1  .  .  .  .
+      20    1  3  1  .  .  .  .  .
+      21    1  1  1  .  .  .  .  .
+      22    1  1  .  .  .  .  .  .
+      23    1  1  .  .  .  .  .  .
+      24    1  1  2  2  2  2  2  1
+      25    1  2  2  2  2  2  1  .
+;
+
+param col : 1  2  3  4  5  6  7  8  :=
+      1     1  2  2  2  2  2  1  .
+      2     1  1  2  2  2  2  2  1
+      3     1  1  .  .  .  .  .  .
+      4     1  1  .  .  .  .  .  .
+      5     1  1  .  .  .  .  .  .
+      6     1  2  1  .  .  .  .  .
+      7     1  6  1  1  .  .  .  .
+      8     1  6  2  1  .  .  .  .
+      9     1  6  3  1  .  .  .  .
+      10    1  4  8  1  .  .  .  .
+      11    1  3  5  2  1  .  .  .
+      12    1  4  8  2  1  .  .  .
+      13    1  4  9  2  1  .  .  .
+      14    1  4  11 1  .  .  .  .
+      15    1  3  9  1  .  .  .  .
+      16    1  4  8  1  .  .  .  .
+      17    1  6  3  1  .  .  .  .
+      18    1  6  2  1  .  .  .  .
+      19    1  6  1  1  .  .  .  .
+      20    1  2  1  .  .  .  .  .
+      21    1  1  .  .  .  .  .  .
+      22    1  1  .  .  .  .  .  .
+      23    1  1  .  .  .  .  .  .
+      24    1  2  2  2  2  2  1  1
+      25    1  2  2  2  2  2  1  .
+;
+
+end;
Index: deps/glpk/examples/pbn/knot.dat
===================================================================
--- deps/glpk/examples/pbn/knot.dat	(revision 9)
+++ deps/glpk/examples/pbn/knot.dat	(revision 9)
@@ -0,0 +1,95 @@
+/* knot.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #16 from <www.webpbn.com>.
+*  Copyright (C) 2004 by Jan Wolter. Used by permission.
+*
+*  Probably Not
+*
+*  created by Jan Wolter
+*  Mar 27, 2004
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 34;
+
+param n := 34;
+
+param row : 1  2  3  4  5  6  7  8 :=
+      1     1  1  .  .  .  .  .  .
+      2     2  2  .  .  .  .  .  .
+      3     3  3  .  .  .  .  .  .
+      4     2  1  1  2  .  .  .  .
+      5     2  1  1  2  .  .  .  .
+      6     1  1  1  1  .  .  .  .
+      7     1  1  1  1  .  .  .  .
+      8     18 .  .  .  .  .  .  .
+      9     2  1  1  1  1  2  .  .
+      10    1  1  1  1  1  1  .  .
+      11    1  1  1  1  1  1  .  .
+      12    26 .  .  .  .  .  .  .
+      13    2  1  1  1  1  1  1  2
+      14    2  1  1  2  2  1  1  2
+      15    2  1  1  2  2  1  1  2
+      16    14 14 .  .  .  .  .  .
+      17    1  1  1  1  .  .  .  .
+      18    1  1  1  1  .  .  .  .
+      19    14 14 .  .  .  .  .  .
+      20    2  1  1  2  2  1  1  2
+      21    2  1  1  2  2  1  1  2
+      22    2  1  1  1  1  1  1  2
+      23    26 .  .  .  .  .  .  .
+      24    1  1  1  1  1  1  .  .
+      25    1  1  1  1  1  1  .  .
+      26    2  1  1  1  1  2  .  .
+      27    18 .  .  .  .  .  .  .
+      28    1  1  1  1  .  .  .  .
+      29    1  1  1  1  .  .  .  .
+      30    2  1  1  2  .  .  .  .
+      31    2  1  1  2  .  .  .  .
+      32    3  3  .  .  .  .  .  .
+      33    2  2  .  .  .  .  .  .
+      34    1  1  .  .  .  .  .  .
+;
+
+param col : 1  2  3  4  5  6  7  8 :=
+      1     1  1  .  .  .  .  .  .
+      2     2  2  .  .  .  .  .  .
+      3     3  3  .  .  .  .  .  .
+      4     2  1  1  2  .  .  .  .
+      5     2  1  1  2  .  .  .  .
+      6     1  1  1  1  .  .  .  .
+      7     1  1  1  1  .  .  .  .
+      8     18 .  .  .  .  .  .  .
+      9     2  1  1  1  1  2  .  .
+      10    1  1  1  1  1  1  .  .
+      11    1  1  1  1  1  1  .  .
+      12    26 .  .  .  .  .  .  .
+      13    2  1  1  1  1  1  1  2
+      14    2  1  1  2  2  1  1  2
+      15    2  1  1  2  2  1  1  2
+      16    14 14 .  .  .  .  .  .
+      17    1  1  1  1  .  .  .  .
+      18    1  1  1  1  .  .  .  .
+      19    14 14 .  .  .  .  .  .
+      20    2  1  1  2  2  1  1  2
+      21    2  1  1  2  2  1  1  2
+      22    2  1  1  1  1  1  1  2
+      23    26 .  .  .  .  .  .  .
+      24    1  1  1  1  1  1  .  .
+      25    1  1  1  1  1  1  .  .
+      26    2  1  1  1  1  2  .  .
+      27    18 .  .  .  .  .  .  .
+      28    1  1  1  1  .  .  .  .
+      29    1  1  1  1  .  .  .  .
+      30    2  1  1  2  .  .  .  .
+      31    2  1  1  2  .  .  .  .
+      32    3  3  .  .  .  .  .  .
+      33    2  2  .  .  .  .  .  .
+      34    1  1  .  .  .  .  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/light.dat
===================================================================
--- deps/glpk/examples/pbn/light.dat	(revision 9)
+++ deps/glpk/examples/pbn/light.dat	(revision 9)
@@ -0,0 +1,122 @@
+/* light.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #803 from <www.webpbn.com>.
+*  Copyright (C) 2007 by Robert Kummerfeldt. Used by permission.
+*
+*  You light up my life
+*
+*  created by Robert Kummerfeldt
+*  Mar 15, 2007
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 45;
+
+param n := 50;
+
+param row : 1  2  3  4  :=
+      1     .  .  .  .
+      2     1  .  .  .
+      3     1  .  .  .
+      4     3  .  .  .
+      5     2  2  .  .
+      6     1  1  .  .
+      7     7  .  .  .
+      8     1  1  .  .
+      9     1  3  1  .
+      10    1  3  1  .
+      11    1  1  .  .
+      12    11 .  .  .
+      13    1  1  .  .
+      14    1  1  .  .
+      15    2  2  .  .
+      16    1  1  .  .
+      17    1  1  .  .
+      18    1  1  .  .
+      19    1  1  .  .
+      20    2  2  .  .
+      21    1  1  .  .
+      22    1  1  .  .
+      23    1  1  .  .
+      24    1  1  .  .
+      25    1  1  .  .
+      26    1  1  .  .
+      27    1  1  .  .
+      28    1  1  .  .
+      29    1  1  .  .
+      30    1  1  .  .
+      31    2  2  .  .
+      32    1  1  .  .
+      33    1  1  .  .
+      34    1  1  .  .
+      35    1  1  .  .
+      36    1  1  .  .
+      37    1  4  1  .
+      38    1  1  1  1
+      39    1  1  1  1
+      40    1  1  1  1
+      41    1  1  1  1
+      42    25 .  .  .
+      43    6  5  .  .
+      44    5  6  .  .
+      45    4  5  .  .
+;
+
+param col : 1  2  3  4  5  :=
+      1     1  .  .  .  .
+      2     1  .  .  .  .
+      3     1  .  .  .  .
+      4     2  .  .  .  .
+      5     1  .  .  .  .
+      6     1  .  .  .  .
+      7     1  .  .  .  .
+      8     2  .  .  .  .
+      9     1  .  .  .  .
+      10    1  .  .  .  .
+      11    1  .  .  .  .
+      12    1  .  .  .  .
+      13    2  .  .  .  .
+      14    1  .  .  .  .
+      15    1  .  .  .  .
+      16    1  .  .  .  .
+      17    5  .  .  .  .
+      18    7  1  .  .  .
+      19    6  1  .  .  .
+      20    6  1  .  .  .
+      21    1  6  1  .  .
+      22    4  1  .  .  .
+      23    7  1  .  .  .
+      24    1  1  1  1  .
+      25    2  1  2  1  1
+      26    3  1  2  1  1
+      27    2  1  2  1  1
+      28    1  1  1  1  .
+      29    7  6  .  .  .
+      30    4  1  1  .  .
+      31    1  6  1  1  .
+      32    6  6  .  .  .
+      33    6  1  .  .  .
+      34    5  1  .  .  .
+      35    7  .  .  .  .
+      36    1  .  .  .  .
+      37    2  .  .  .  .
+      38    1  .  .  .  .
+      39    1  .  .  .  .
+      40    1  .  .  .  .
+      41    2  .  .  .  .
+      42    1  .  .  .  .
+      43    1  .  .  .  .
+      44    1  .  .  .  .
+      45    1  .  .  .  .
+      46    2  .  .  .  .
+      47    1  .  .  .  .
+      48    1  .  .  .  .
+      49    1  .  .  .  .
+      50    1  .  .  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/mum.dat
===================================================================
--- deps/glpk/examples/pbn/mum.dat	(revision 9)
+++ deps/glpk/examples/pbn/mum.dat	(revision 9)
@@ -0,0 +1,101 @@
+/* mum.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #65 from <www.webpbn.com>.
+*  Copyright (C) 2004 by Jan Wolter. Used by permission.
+*
+*  Mum's the Word [has only one solution]
+*
+*  created by Jan Wolter
+*  Jul 10, 2004
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 40;
+
+param n := 34;
+
+param row : 1  2  3  4  5  6  7  8  9  :=
+      1     12 .  .  .  .  .  .  .  .
+      2     5  2  5  .  .  .  .  .  .
+      3     5  2  2  5  .  .  .  .  .
+      4     1  2  2  2  2  2  1  .  .
+      5     4  2  2  4  2  2  4  .  .
+      6     4  2  2  4  2  2  4  .  .
+      7     1  2  2  2  2  2  1  .  .
+      8     6  2  2  2  2  2  6  .  .
+      9     6  2  2  2  2  2  6  .  .
+      10    1  14 1  .  .  .  .  .  .
+      11    10 10 .  .  .  .  .  .  .
+      12    8  3  3  8  .  .  .  .  .
+      13    1  1  2  1  1  2  1  1  .
+      14    9  2  2  2  2  9  .  .  .
+      15    9  9  .  .  .  .  .  .  .
+      16    1  1  1  1  1  1  .  .  .
+      17    12 2  12 .  .  .  .  .  .
+      18    12 12 .  .  .  .  .  .  .
+      19    1  1  4  1  1  .  .  .  .
+      20    14 14 .  .  .  .  .  .  .
+      21    12 12 .  .  .  .  .  .  .
+      22    2  1  4  1  2  .  .  .  .
+      23    9  4  9  .  .  .  .  .  .
+      24    1  7  4  7  1  .  .  .  .
+      25    1  1  1  4  1  1  1  .  .
+      26    1  7  4  7  1  .  .  .  .
+      27    1  7  4  7  1  .  .  .  .
+      28    1  2  1  2  1  2  1  .  .
+      29    1  7  2  7  1  .  .  .  .
+      30    1  1  6  2  6  1  1  .  .
+      31    1  1  1  1  2  1  1  1  1
+      32    1  1  6  2  6  1  1  .  .
+      33    1  1  5  5  1  1  .  .  .
+      34    1  1  1  8  1  1  1  .  .
+      35    1  1  4  4  1  1  .  .  .
+      36    1  2  6  2  1  .  .  .  .
+      37    2  4  4  2  .  .  .  .  .
+      38    2  6  2  .  .  .  .  .  .
+      39    4  4  .  .  .  .  .  .  .
+      40    6  .  .  .  .  .  .  .  .
+;
+
+param col : 1  2  3  4  5  6  7  8  9  10 11 12 :=
+      1     5  .  .  .  .  .  .  .  .  .  .  .
+      2     3  2  1  .  .  .  .  .  .  .  .  .
+      3     3  2  2  1  .  .  .  .  .  .  .  .
+      4     3  2  2  2  2  .  .  .  .  .  .  .
+      5     3  2  2  2  2  3  .  .  .  .  .  .
+      6     1  2  2  2  2  2  16 .  .  .  .  .
+      7     1  2  2  2  2  2  2  1  2  .  .  .
+      8     1  2  2  2  2  2  2  13 1  .  .  .
+      9     3  2  2  2  2  2  2  4  1  1  .  .
+      10    6  5  2  2  2  2  6  1  1  .  .  .
+      11    1  7  3  2  2  2  2  2  1  1  1  .
+      12    3  4  1  2  2  2  2  2  2  1  1  1
+      13    6  1  2  3  2  2  2  2  1  1  1  .
+      14    1  7  2  16 1  1  .  .  .  .  .  .
+      15    1  4  1  1  1  1  1  1  1  1  1  .
+      16    1  2  1  3  1  1  6  1  1  1  1  .
+      17    2  7  1  1  11 1  1  1  1  .  .  .
+      18    2  7  1  1  11 1  1  1  1  .  .  .
+      19    1  2  1  3  1  1  6  1  1  1  1  .
+      20    1  4  1  1  1  1  1  1  1  1  1  .
+      21    1  7  2  16 1  1  .  .  .  .  .  .
+      22    6  1  2  3  2  2  2  2  1  1  1  .
+      23    3  4  1  2  2  2  2  2  2  1  1  1
+      24    1  7  3  2  2  2  2  2  1  1  1  .
+      25    6  5  2  2  2  2  6  1  1  .  .  .
+      26    3  2  2  2  2  2  2  4  1  1  .  .
+      27    1  2  2  2  2  2  2  13 1  .  .  .
+      28    1  2  2  2  2  2  2  1  2  .  .  .
+      29    1  2  2  2  2  2  16 .  .  .  .  .
+      30    3  2  2  2  2  3  .  .  .  .  .  .
+      31    3  2  2  2  2  .  .  .  .  .  .  .
+      32    3  2  2  1  .  .  .  .  .  .  .  .
+      33    3  2  1  .  .  .  .  .  .  .  .  .
+      34    5  .  .  .  .  .  .  .  .  .  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/pbn.mod
===================================================================
--- deps/glpk/examples/pbn/pbn.mod	(revision 9)
+++ deps/glpk/examples/pbn/pbn.mod	(revision 9)
@@ -0,0 +1,268 @@
+/* PBN, Paint-By-Numbers Puzzle */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* NOTE: See also the document "Solving Paint-By-Numbers Puzzles with
+         GLPK", which is included in the GLPK distribution. */
+
+/* A paint-by-numbers puzzle consists of an m*n grid of pixels (the
+   canvas) together with m+n cluster-size sequences, one for each row
+   and column. The goal is to paint the canvas with a picture that
+   satisfies the following constraints:
+
+   1. Each pixel must be blank or white.
+
+   2. If a row or column has cluster-size sequence s1, s2, ..., sk,
+      then it must contain k clusters of black pixels - the first with
+      s1 black pixels, the second with s2 black pixels, and so on.
+
+   It should be noted that "first" means "leftmost" for rows and
+   "topmost" for columns, and that rows and columns need not begin or
+   end with black pixels.
+
+   Example:
+                  1   1
+                  1   1
+              2 1 1 1 1 1 2 3
+              3 2 1 2 1 2 3 4 8 9
+
+        3 6   # # # . # # # # # #
+        1 4   # . . . . . # # # #
+      1 1 3   . . # . # . . # # #
+          2   . . . . . . . . # #
+        3 3   . . # # # . . # # #
+        1 4   # . . . . . # # # #
+        2 5   # # . . . # # # # #
+        2 5   # # . . . # # # # #
+        1 1   . . . # . . . . . #
+          3   . . # # # . . . . .
+
+   (In Russia such puzzles are known as "Japanese crosswords".)
+
+   References:
+   Robert A. Bosch, "Painting by Numbers", 2000.
+   <http://www.oberlin.edu/~math/faculty/bosch/pbn-page.html> */
+
+/*--------------------------------------------------------------------*/
+/* Main part based on the formulation proposed by Robert Bosch. */
+
+param m, integer, >= 1;
+/* the number of rows */
+
+param n, integer, >= 1;
+/* the number of columns */
+
+param row{i in 1..m, 1..n div 2}, integer, >= 0, default 0;
+/* the cluster-size sequence for row i (raw data) */
+
+param col{j in 1..n, 1..m div 2}, integer, >= 0, default 0;
+/* the cluster-size sequence for column j (raw data) */
+
+param kr{i in 1..m} := sum{t in 1..n div 2: row[i,t] > 0} 1;
+/* the number of clusters in row i */
+
+param kc{j in 1..n} := sum{t in 1..m div 2: col[j,t] > 0} 1;
+/* the number of clusters in column j */
+
+param sr{i in 1..m, t in 1..kr[i]} := row[i,t], integer, >= 1;
+/* the cluster-size sequence for row i */
+
+param sc{j in 1..n, t in 1..kc[j]} := col[j,t], integer, >= 1;
+/* the cluster-size sequence for column j */
+
+check{i in 1..m}: sum{t in 1..kr[i]} sr[i,t] <= n - (kr[i] - 1);
+/* check that the sum of the cluster sizes in each row is valid */
+
+check{j in 1..n}: sum{t in 1..kc[j]} sc[j,t] <= m - (kc[j] - 1);
+/* check that the sum of the cluster sizes in each column is valid */
+
+check: sum{i in 1..m, t in 1..kr[i]} sr[i,t] =
+       sum{j in 1..n, t in 1..kc[j]} sc[j,t];
+/* check that the sum of the cluster sizes in all rows is equal to the
+   sum of the cluster sizes in all columns */
+
+param er{i in 1..m, t in 1..kr[i]} :=
+   if t = 1 then 1 else er[i,t-1] + sr[i,t-1] + 1;
+/* the smallest value of j such that row i's t-th cluster can be
+   placed in row i with its leftmost pixel occupying pixel j */
+
+param lr{i in 1..m, t in 1..kr[i]} :=
+   if t = kr[i] then n + 1 - sr[i,t] else lr[i,t+1] - sr[i,t] - 1;
+/* the largest value of j such that row i's t-th cluster can be
+   placed in row i with its leftmost pixel occupying pixel j */
+
+param ec{j in 1..n, t in 1..kc[j]} :=
+   if t = 1 then 1 else ec[j,t-1] + sc[j,t-1] + 1;
+/* the smallest value of i such that column j's t-th cluster can be
+   placed in column j with its topmost pixel occupying pixel i */
+
+param lc{j in 1..n, t in 1..kc[j]} :=
+   if t = kc[j] then m + 1 - sc[j,t] else lc[j,t+1] - sc[j,t] - 1;
+/* the largest value of i such that column j's t-th cluster can be
+   placed in column j with its topmost pixel occupying pixel i */
+
+var z{i in 1..m, j in 1..n}, binary;
+/* z[i,j] = 1, if row i's j-th pixel is painted black
+   z[i,j] = 0, if row i's j-th pixel is painted white */
+
+var y{i in 1..m, t in 1..kr[i], j in er[i,t]..lr[i,t]}, binary;
+/* y[i,t,j] = 1, if row i's t-th cluster is placed in row i with its
+                 leftmost pixel occupying pixel j
+   y[i,t,j] = 0, if not */
+
+var x{j in 1..n, t in 1..kc[j], i in ec[j,t]..lc[j,t]}, binary;
+/* x[j,t,i] = 1, if column j's t-th cluster is placed in column j with
+                 its topmost pixel occupying pixel i
+   x[j,t,i] = 0, if not */
+
+s.t. fa{i in 1..m, t in 1..kr[i]}:
+     sum{j in er[i,t]..lr[i,t]} y[i,t,j] = 1;
+/* row i's t-th cluster must appear in row i exactly once */
+
+s.t. fb{i in 1..m, t in 1..kr[i]-1, j in er[i,t]..lr[i,t]}:
+     y[i,t,j] <= sum{jp in j+sr[i,t]+1..lr[i,t+1]} y[i,t+1,jp];
+/* row i's (t+1)-th cluster must be placed to the right of its t-th
+   cluster */
+
+s.t. fc{j in 1..n, t in 1..kc[j]}:
+     sum{i in ec[j,t]..lc[j,t]} x[j,t,i] = 1;
+/* column j's t-th cluster must appear in column j exactly once */
+
+s.t. fd{j in 1..n, t in 1..kc[j]-1, i in ec[j,t]..lc[j,t]}:
+     x[j,t,i] <= sum{ip in i+sc[j,t]+1..lc[j,t+1]} x[j,t+1,ip];
+/* column j's (t+1)-th cluster must be placed below its t-th cluster */
+
+s.t. fe{i in 1..m, j in 1..n}:
+     z[i,j] <= sum{t in 1..kr[i], jp in er[i,t]..lr[i,t]:
+                   j-sr[i,t]+1 <= jp and jp <= j} y[i,t,jp];
+/* the double coverage constraint stating that if row i's j-th pixel
+   is painted black, then at least one of row i's clusters must be
+   placed in such a way that it covers row i's j-th pixel */
+
+s.t. ff{i in 1..m, j in 1..n}:
+     z[i,j] <= sum{t in 1..kc[j], ip in ec[j,t]..lc[j,t]:
+                   i-sc[j,t]+1 <= ip and ip <= i} x[j,t,ip];
+/* the double coverage constraint making sure that if row i's j-th
+   pixel is painted black, then at least one of column j's clusters
+   covers it */
+
+s.t. fg{i in 1..m, j in 1..n, t in 1..kr[i], jp in er[i,t]..lr[i,t]:
+     j-sr[i,t]+1 <= jp and jp <= j}: z[i,j] >= y[i,t,jp];
+/* the constraint to prevent white pixels from being covered by the
+   row clusters */
+
+s.t. fh{i in 1..m, j in 1..n, t in 1..kc[j], ip in ec[j,t]..lc[j,t]:
+     i-sc[j,t]+1 <= ip and ip <= i}: z[i,j] >= x[j,t,ip];
+/* the constraint to prevent white pixels from being covered by the
+   column clusters */
+
+/* this is a feasibility problem, so no objective is needed */
+
+/*--------------------------------------------------------------------*/
+/* The following part is used only to check for multiple solutions. */
+
+param zz{i in 1..m, j in 1..n}, binary, default 0;
+/* zz[i,j] is z[i,j] for a previously found solution */
+
+s.t. fz{1..1 : sum{i in 1..m, j in 1..n} zz[i,j] > 0}:
+     sum{i in 1..m, j in 1..n}
+         (if zz[i,j] then (1 - z[i,j]) else z[i,j]) >= 1;
+/* the constraint to forbid finding a solution, which is identical to
+   the previously found one; this constraint is included in the model
+   only if the previously found solution specified by the parameter zz
+   is provided in the data section */
+
+solve;
+
+/*--------------------------------------------------------------------*/
+/* Print solution to the standard output. */
+
+for {i in 1..m}
+{  printf{j in 1..n} " %s", if z[i,j] then "#" else ".";
+   printf "\n";
+}
+
+/*--------------------------------------------------------------------*/
+/* Write solution to a text file in PostScript format. */
+
+param ps, symbolic, default "solution.ps";
+
+printf "%%!PS-Adobe-3.0\n" > ps;
+printf "%%%%Creator: GLPK (pbn.mod)\n" >> ps;
+printf "%%%%BoundingBox: 0 0 %d %d\n",
+       6 * (n + 2), 6 * (m + 2) >> ps;
+printf "%%%%EndComments\n" >> ps;
+printf "<</PageSize [%d %d]>> setpagedevice\n",
+       6 * (n + 2), 6 * (m + 2) >> ps;
+printf "0.1 setlinewidth\n" >> ps;
+printf "/A { 2 copy 2 copy 2 copy newpath moveto exch 6 add exch line" &
+       "to\n" >> ps;
+printf "exch 6 add exch 6 add lineto 6 add lineto closepath } bind de" &
+       "f\n" >> ps;
+printf "/W { A stroke } def\n" >> ps;
+printf "/B { A fill } def\n" >> ps;
+printf {i in 1..m, j in 1..n} "%d %d %s\n",
+       (j - 1) * 6 + 6, (m - i) * 6 + 6,
+       if z[i,j] then "B" else "W" >> ps;
+printf "%%%%EOF\n" >> ps;
+
+printf "Solution has been written to file %s\n", ps;
+
+/*--------------------------------------------------------------------*/
+/* Write solution to a text file in the form of MathProg data section,
+   which can be used later to check for multiple solutions. */
+
+param dat, symbolic, default "solution.dat";
+
+printf "data;\n" > dat;
+printf "\n" >> dat;
+printf "param zz :" >> dat;
+printf {j in 1..n} " %d", j >> dat;
+printf " :=\n" >> dat;
+for {i in 1..m}
+{  printf " %2d", i >> dat;
+   printf {j in 1..n} " %s", if z[i,j] then "1" else "." >> dat;
+   printf "\n" >> dat;
+}
+printf ";\n" >> dat;
+printf "\n" >> dat;
+printf "end;\n" >> dat;
+
+printf "Solution has also been written to file %s\n", dat;
+
+/*--------------------------------------------------------------------*/
+/* The following data correspond to the example above. */
+
+data;
+
+param m := 10;
+
+param n := 10;
+
+param row : 1  2  3  :=
+      1     3  6  .
+      2     1  4  .
+      3     1  1  3
+      4     2  .  .
+      5     3  3  .
+      6     1  4  .
+      7     2  5  .
+      8     2  5  .
+      9     1  1  .
+      10    3  .  .
+;
+
+param col : 1  2  3  4  :=
+      1     2  3  .  .
+      2     1  2  .  .
+      3     1  1  1  1
+      4     1  2  .  .
+      5     1  1  1  1
+      6     1  2  .  .
+      7     2  3  .  .
+      8     3  4  .  .
+      9     8  .  .  .
+      10    9  .  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/pbn.tex
===================================================================
--- deps/glpk/examples/pbn/pbn.tex	(revision 9)
+++ deps/glpk/examples/pbn/pbn.tex	(revision 9)
@@ -0,0 +1,279 @@
+%* pbn.tex *%
+
+\documentclass[11pt,draft]{article}
+\usepackage{amssymb}
+
+\begin{document}
+
+\title{Solving Paint-By-Numbers Puzzles with GLPK}
+
+\author{Andrew Makhorin {\tt<mao@gnu.org>}}
+
+\date{August 2011}
+
+\maketitle
+
+\section{Introduction$^1$}
+
+\footnotetext[1]{This section is based on the material from [1].}
+
+A {\it paint-by-numbers} puzzle consists of an $m\times n$ grid of
+pixels (the {\it canvas}) together with $m+n$ {\it cluster-size
+sequences}, one for each row and column. The goal is to paint the canvas
+with a picture that satisfies the following constraints:
+
+1. Each pixel must be blank or white.
+
+2. If a row or column has cluster-size sequence $s_1$, $s_2$, \dots,
+$s_k$, then it must contain $k$ clusters of black pixels---the first
+with $s_1$ black pixels, the second with $s_2$ black pixels, and so on.
+
+It should be noted that ``first'' means ``leftmost'' for rows and
+``topmost'' for columns, and that rows and columns need not begin or end
+with black pixels.
+
+\subsubsection*{Example}
+
+\def\arraystretch{.8}
+
+\begin{center}
+\begin{tabular}{*{3}{@{$\;\;$}c}c*{10}{@{\ }c}@{}}
+ & & && & &1& &1& & & & & \\
+ & & && & &1& &1& & & & & \\
+ & & &&2&1&1&1&1&1&2&3& & \\
+ & & &&3&2&1&2&1&2&3&4&8&9\\
+\\
+ &3&6&&$\blacksquare$&$\blacksquare$&$\blacksquare$&$\square$&
+$\blacksquare$&$\blacksquare$&$\blacksquare$&$\blacksquare$&
+$\blacksquare$&$\blacksquare$\\
+ &1&4&&$\blacksquare$&$\square$&$\square$&$\square$&$\square$&
+$\square$&$\blacksquare$&$\blacksquare$&$\blacksquare$&$\blacksquare$\\
+1&1&3&&$\square$&$\square$&$\blacksquare$&$\square$&$\blacksquare$&
+$\square$&$\square$&$\blacksquare$&$\blacksquare$&$\blacksquare$\\
+ & &2&&$\square$&$\square$&$\square$&$\square$&$\square$&$\square$&
+$\square$&$\square$&$\blacksquare$&$\blacksquare$\\
+ &3&3&&$\square$&$\square$&$\blacksquare$&$\blacksquare$&$\blacksquare$&
+$\square$&$\square$&$\blacksquare$&$\blacksquare$&$\blacksquare$\\
+ &1&4&&$\blacksquare$&$\square$&$\square$&$\square$&$\square$&$\square$&
+$\blacksquare$&$\blacksquare$&$\blacksquare$&$\blacksquare$\\
+ &2&5&&$\blacksquare$&$\blacksquare$&$\square$&$\square$&$\square$&
+$\blacksquare$&$\blacksquare$&$\blacksquare$&$\blacksquare$&
+$\blacksquare$\\
+ &2&5&&$\blacksquare$&$\blacksquare$&$\square$&$\square$&$\square$&
+$\blacksquare$&$\blacksquare$&$\blacksquare$&$\blacksquare$&
+$\blacksquare$\\
+ &1&1&&$\square$&$\square$&$\square$&$\blacksquare$&$\square$&$\square$&
+$\square$&$\square$&$\square$&$\blacksquare$\\
+ & &3&&$\square$&$\square$&$\blacksquare$&$\blacksquare$&$\blacksquare$&
+$\square$&$\square$&$\square$&$\square$&$\square$\\
+\end{tabular}
+\end{center}
+
+\def\arraystretch{1}
+
+\section{Solving a puzzle}
+
+The Paint-By-Numbers puzzle can be formulated as a 0-1 integer
+feasibility problem. The formulation used in GLPK was proposed in [1].
+
+For solving puzzles there are used two components, which both are
+coded in the GNU MathProg modeling language [2]: the model section and
+the data section. The model section is common for all puzzles and
+placed in file \verb|pbn.mod|. This file is included in the GLPK
+distribution and can be found in subdirectory \verb|examples/pbn|.
+
+To solve a particular puzzle the user only needs to prepare the data
+section, which defines input data to the puzzle. The data section for
+the example puzzle from the previous section may look like follows
+(here \verb|m| is the number of rows, and \verb|n| is the number of
+columns):
+
+\begin{footnotesize}
+\begin{verbatim}
+data;
+
+param m := 10;
+
+param n := 10;
+
+param row : 1  2  3  :=
+      1     3  6  .
+      2     1  4  .
+      3     1  1  3
+      4     2  .  .
+      5     3  3  .
+      6     1  4  .
+      7     2  5  .
+      8     2  5  .
+      9     1  1  .
+      10    3  .  .
+;
+
+param col : 1  2  3  4  :=
+      1     2  3  .  .
+      2     1  2  .  .
+      3     1  1  1  1
+      4     1  2  .  .
+      5     1  1  1  1
+      6     1  2  .  .
+      7     2  3  .  .
+      8     3  4  .  .
+      9     8  .  .  .
+      10    9  .  .  .
+;
+
+end;
+\end{verbatim}
+\end{footnotesize}
+
+\newpage
+
+Let the data section for a puzzle be placed in file \verb|foo.dat|.
+Then to solve the puzzle the user should enter the following command:
+
+\begin{verbatim}
+   glpsol --minisat -m pbn.mod -d foo.dat
+\end{verbatim}
+
+\noindent
+This command invokes \verb|glpsol|, the GLPK LP/MIP stand-alone solver,
+which reads the model section from file \verb|pbn.mod|, the data section
+from file \verb|foo.dat|, translates them to an internal representation,
+and solves the resulting 0-1 integer feasibility problem. The option
+\verb|--minisat| tells \verb|glpsol| to translate the feasibility
+problem to a CNF satisfiability problem and then use the MiniSat solver
+[3] to solve it.
+
+If a solution to the puzzle has been found, that is indicated by the
+message \verb|SATISFIABLE|, \verb|glpsol| prints the solution to the
+standard output (terminal), writes it to file \verb|solution.ps| in the
+PostScript format, and also writes it to file \verb|solution.dat| in the
+form of MathProg data section, which can be used later to check for
+multiple solutions, if necessary (for details see the next section).
+The message \verb|UNSATISFIABLE| means that the puzzle has no solution.
+
+Usually the time taken to solve a puzzle of moderate size (up to 50 rows
+and columns) varies from several seconds to several minutes. However,
+hard or large puzzles may require much more time.
+
+Data sections for some example puzzles included in the GLPK distribution
+can be found in subdirectory \verb|examples/pbn|.
+
+\section{Checking for multiple solutions}
+
+Sometimes the user may be interested to know if the puzzle has exactly
+one (unique) solution or it has multiple solutions. To check that the
+user should solve the puzzle as explained above in the previous section
+and then enter the following command:
+
+\begin{verbatim}
+   glpsol --minisat -m pbn.mod -d foo.dat -d solution.dat
+\end{verbatim}
+
+\noindent
+In this case \verb|glpsol| reads an additional data section from file
+\verb|solution.dat|, which contains the previously found solution,
+activates an additional constraint in the model section to forbid
+finding the solution specified in the additional data section, and
+attempts to find another solution. The message \verb|UNSATISFIABLE|
+reported by \verb|glpsol| will mean that the puzzle has a unique
+solution, while the message \verb|SATISFIABLE| will mean that the puzzle
+has at least two different solutions.
+
+\newpage
+
+\section{Solution times}
+
+The table on the next page shows solution times on a sample set of
+the paint-by-numbers puzzles from the \verb|<webpbn.com>| website.
+This sample set was used in the survey [4] to compare efficiency of
+existing PBN solvers.
+
+The authors of some puzzles from the sample set have given permission
+for their puzzles to be freely redistributed as long as the original
+attribution and copyright statement are retained. In the table these
+puzzles are marked by an asterisk (*). The files containing the
+MathProg data sections for these puzzles are included in the GLPK
+distribution and can be found in subdirectory \verb|examples/pbn|.
+
+All runs were performed on Intel Pentium 4 (CPU 3GHz, 2GB of RAM).
+The C compiler used was GCC 3.4.4 with default optimization options.
+
+The column `Sol.Time' shows the time, in seconds, taken by the
+\verb|glpsol| solver to find a solution to corresponding puzzle. The
+column `Chk.Time' shows the time, in seconds, taken by \verb|glpsol| to
+check for multiple solutions, i.e. either to prove that the puzzle has
+a unique solution or find another solution to the puzzle. Both these
+times do not include the time used to translate the MathProg model and
+data sections into an internal MIP representation, but include the time
+used to translate the 0-1 feasibility problem to a CNF satisfiability
+problem.
+
+\begin{thebibliography}{10}
+
+\bibitem{1}
+Robert A. Bosch, ``Painting by Numbers'', 2000.\\
+\verb|<http://www.oberlin.edu/~math/faculty/bosch/pbn-page.html>|.
+
+\bibitem{2}
+GLPK: Modeling Language GNU MathProg. Language Reference. (This
+document is included in the GLPK distribution and can be found in
+subdirectory \verb|doc|.)
+
+\bibitem{3}
+Niklas E\'en, Niklas S\"orensson, ``An Extensible SAT-solver'',
+Chalmers University of Technology, Sweden. \verb|<http://minisat.se/>|.
+
+\bibitem{4}
+Jan Wolter, ``Survey of Paint-by-Number Puzzle Solvers''.\\
+\verb|<http://webpbn.com/survey/>|.
+
+\end{thebibliography}
+
+\newpage
+
+\begin{table}
+\caption{Solution times on the sample set of puzzles from [4]}
+\begin{center}
+\begin{tabular}{@{}lllcrr@{}}
+\hline
+\multicolumn{2}{c}{Puzzle}&Size&Notes&Sol.Time, s&Chk.Time, s\\
+\hline
+\#1&Dancer*    &$10\times 5$&L&$<1$&$<1$\\
+\#6&Cat*       &$20\times 20$&L&$<1$&$<1$\\
+\#21&Skid*     &$25\times 14$&L, B&$<1$&$<1$\\
+\#27&Bucks*    &$23\times 27$&B&$<1$&$<1$\\
+\#23&Edge*     &$11\times 10$&&$<1$&$<1$\\
+\#2413&Smoke   &$20\times 20$&&$<1$&$<1$\\
+\#16&Knot*     &$34\times 34$&L&1&1\\
+\#529&Swing*   &$45\times 45$&L&1&1\\
+\#65&Mum*      &$40\times 34$&&1&1\\
+\#7604&DiCap   &$55\times 55$&&10&10\\
+\#1694&Tragic  &$50\times 45$&&3&3\\
+\#1611&Merka   &$60\times 55$&B&4&4\\
+\#436&Petro*   &$35\times 40$&&1&1\\
+\#4645&M\&M    &$70\times 50$&B&5&6\\
+\#3541&Signed  &$50\times 60$&&7&7\\
+\#803&Light*   &$45\times 50$&B&1&1\\
+\#6574&Forever*&$25\times 25$&&1&1\\
+\#2040&Hot     &$60\times 55$&&6&6\\
+\#6739&Karate  &$40\times 40$&M&2&2\\
+\#8098&9-Dom*  &$19\times 19$&&1&2\\
+\#2556&Flag    &$45\times 65$&M, B&2&2\\
+\#2712&Lion    &$47\times 47$&M&11&12\\
+\#10088&Marley &$63\times 52$&M&135&226\\
+\#9892&Nature  &$40\times 50$&M&850&1053\\
+\hline
+\end{tabular}
+
+\begin{tabular}{@{}lp{102mm}@{}}
+*&Puzzle designer has given permission to redistribute the puzzle.\\
+L&Puzzle is line solvable. That is, it can be solved one line at a
+time.\\
+B&Puzzle contains blank rows or columns.\\
+M&Puzzle has multiple solutions.\\
+\end{tabular}
+\end{center}
+\end{table}
+
+\end{document}
Index: deps/glpk/examples/pbn/petro.dat
===================================================================
--- deps/glpk/examples/pbn/petro.dat	(revision 9)
+++ deps/glpk/examples/pbn/petro.dat	(revision 9)
@@ -0,0 +1,102 @@
+/* petro.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #436 from <www.webpbn.com>.
+*  Copyright (C) 2006 by Jan Wolter. Used by permission.
+*
+*  Old Stone Face
+*
+*  created by Jan Wolter
+*  Jun 17, 2006
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 35;
+
+param n := 40;
+
+param row : 1  2  3  4  5  6  7  8  9  :=
+      1     2  2  .  .  .  .  .  .  .
+      2     2  3  2  .  .  .  .  .  .
+      3     3  3  3  2  .  .  .  .  .
+      4     3  3  3  3  .  .  .  .  .
+      5     2  3  3  3  3  2  .  .  .
+      6     3  3  3  3  3  3  .  .  .
+      7     4  2  3  2  2  4  .  .  .
+      8     4  2  2  2  2  3  1  .  .
+      9     3  1  2  2  2  3  3  .  .
+      10    3  2  2  2  2  2  4  .  .
+      11    3  2  15 2  4  .  .  .  .
+      12    5  19 4  .  .  .  .  .  .
+      13    6  4  3  3  .  .  .  .  .
+      14    6  4  4  .  .  .  .  .  .
+      15    2  4  6  2  .  .  .  .  .
+      16    2  2  3  3  3  2  .  .  .
+      17    9  2  2  2  3  9  .  .  .
+      18    10 2  2  2  2  2  10 .  .
+      19    4  2  3  3  2  2  3  2  5
+      20    2  5  2  4  2  .  .  .  .
+      21    5  3  2  2  5  .  .  .  .
+      22    6  3  2  3  7  .  .  .  .
+      23    6  8  9  7  .  .  .  .  .
+      24    4  8  7  5  .  .  .  .  .
+      25    4  .  .  .  .  .  .  .  .
+      26    2  .  .  .  .  .  .  .  .
+      27    2  .  .  .  .  .  .  .  .
+      28    14 .  .  .  .  .  .  .  .
+      29    16 .  .  .  .  .  .  .  .
+      30    3  3  .  .  .  .  .  .  .
+      31    2  2  .  .  .  .  .  .  .
+      32    2  2  .  .  .  .  .  .  .
+      33    4  4  .  .  .  .  .  .  .
+      34    16 .  .  .  .  .  .  .  .
+      35    12 .  .  .  .  .  .  .  .
+;
+
+param col : 1  2  3  4  5  6  7  :=
+      1     1  .  .  .  .  .  .
+      2     3  2  .  .  .  .  .
+      3     2  3  3  .  .  .  .
+      4     3  3  3  .  .  .  .
+      5     3  3  3  3  .  .  .
+      6     4  2  2  2  .  .  .
+      7     3  3  2  3  .  .  .
+      8     3  2  2  2  .  .  .
+      9     3  2  6  .  .  .  .
+      10    2  9  .  .  .  .  .
+      11    2  3  3  .  .  .  .
+      12    4  4  3  2  4  .  .
+      13    7  2  5  2  6  .  .
+      14    12 2  3  2  3  2  .
+      15    3  1  2  2  2  3  .
+      16    2  2  3  2  2  2  .
+      17    6  2  6  2  2  2  .
+      18    12 4  3  2  2  .  .
+      19    12 2  2  2  .  .  .
+      20    2  6  2  .  .  .  .
+      21    2  6  5  2  .  .  .
+      22    10 9  2  2  .  .  .
+      23    12 3  3  2  2  .  .
+      24    6  2  2  2  2  2  2
+      25    2  2  3  2  2  2  .
+      26    4  3  2  2  2  3  .
+      27    7  3  3  2  3  2  .
+      28    5  3  5  2  6  .  .
+      29    4  3  3  3  4  .  .
+      30    3  5  3  .  .  .  .
+      31    3  9  .  .  .  .  .
+      32    4  2  6  .  .  .  .
+      33    4  2  2  2  .  .  .
+      34    4  2  2  3  .  .  .
+      35    3  2  2  3  .  .  .
+      36    3  3  3  .  .  .  .
+      37    3  3  3  .  .  .  .
+      38    4  3  3  .  .  .  .
+      39    2  3  3  .  .  .  .
+      40    2  1  .  .  .  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/skid.dat
===================================================================
--- deps/glpk/examples/pbn/skid.dat	(revision 9)
+++ deps/glpk/examples/pbn/skid.dat	(revision 9)
@@ -0,0 +1,66 @@
+/* skid.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #21 from <www.webpbn.com>.
+*  Copyright (C) 2004 by Jan Wolter. Used by permission.
+*
+*  Slippery Conditions
+*
+*  created by Jan Wolter
+*  Apr 4, 2004
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 25;
+
+param n := 14;
+
+param row : 1  2  3  :=
+      1     9  .  .
+      2     1  1  .
+      3     1  1  1
+      4     1  3  1
+      5     13 .  .
+      6     13 .  .
+      7     13 .  .
+      8     13 .  .
+      9     2  2  .
+      10    2  2  .
+      11    .  .  .
+      12    2  2  .
+      13    2  2  .
+      14    2  2  .
+      15    2  2  .
+      16    2  2  .
+      17    2  2  .
+      18    2  2  .
+      19    2  2  .
+      20    2  2  .
+      21    2  2  .
+      22    2  2  .
+      23    2  2  .
+      24    2  2  .
+      25    2  2  .
+;
+
+param col : 1  2  3  4  5  :=
+      1     2  .  .  .  .
+      2     4  6  .  .  .
+      3     9  4  4  2  .
+      4     1  6  2  6  .
+      5     1  5  2  .  .
+      6     1  6  .  .  .
+      7     1  5  .  .  .
+      8     1  4  .  .  .
+      9     1  4  .  .  .
+      10    1  4  2  .  .
+      11    1  4  6  .  .
+      12    1  6  4  4  2
+      13    9  2  6  .  .
+      14    4  2  .  .  .
+;
+
+end;
Index: deps/glpk/examples/pbn/swing.dat
===================================================================
--- deps/glpk/examples/pbn/swing.dat	(revision 9)
+++ deps/glpk/examples/pbn/swing.dat	(revision 9)
@@ -0,0 +1,117 @@
+/* swing.dat */
+
+/***********************************************************************
+*  Web Paint-by-Number Puzzle #529 from <www.webpbn.com>.
+*  Copyright (C) 2006 by Jan Wolter. Used by permission.
+*
+*  Swing
+*
+*  created by Jan Wolter
+*  Sep 28, 2006
+*
+*  Encoded in GNU MathProg by Andrew Makhorin <mao@gnu.org>.
+***********************************************************************/
+
+data;
+
+param m := 45;
+
+param n := 45;
+
+param row : 1  2  3  4  5  6  7  8  9  10 11 12 13 14 :=
+      1     7  1  1  1  1  1  .  .  .  .  .  .  .  .
+      2     3  1  3  1  4  1  4  1  5  1  5  1  2  .
+      3     1  1  1  3  1  4  1  4  1  5  1  5  1  2
+      4     2  1  2  1  1  1  1  6  2  .  .  .  .  .
+      5     3  30 1  5  .  .  .  .  .  .  .  .  .  .
+      6     1  5  8  1  1  7  1  1  3  .  .  .  .  .
+      7     3  4  8  1  5  1  2  .  .  .  .  .  .  .
+      8     3  20 6  6  .  .  .  .  .  .  .  .  .  .
+      9     3  3  7  2  5  1  .  .  .  .  .  .  .  .
+      10    3  3  1  1  9  1  1  5  6  .  .  .  .  .
+      11    2  3  8  1  3  4  2  .  .  .  .  .  .  .
+      12    5  3  1  10 4  5  2  .  .  .  .  .  .  .
+      13    1  2  3  8  4  6  .  .  .  .  .  .  .  .
+      14    2  2  3  11 10 .  .  .  .  .  .  .  .  .
+      15    2  2  3  10 7  .  .  .  .  .  .  .  .  .
+      16    2  3  1  7  12 2  .  .  .  .  .  .  .  .
+      17    2  3  1  4  11 2  .  .  .  .  .  .  .  .
+      18    4  1  2  1  11 2  .  .  .  .  .  .  .  .
+      19    9  1  2  9  .  .  .  .  .  .  .  .  .  .
+      20    6  2  1  4  11 .  .  .  .  .  .  .  .  .
+      21    2  5  1  2  6  6  .  .  .  .  .  .  .  .
+      22    6  2  4  8  4  .  .  .  .  .  .  .  .  .
+      23    4  2  16 1  .  .  .  .  .  .  .  .  .  .
+      24    2  2  15 2  .  .  .  .  .  .  .  .  .  .
+      25    3  2  15 4  .  .  .  .  .  .  .  .  .  .
+      26    3  3  13 4  .  .  .  .  .  .  .  .  .  .
+      27    4  12 9  .  .  .  .  .  .  .  .  .  .  .
+      28    1  9  10 .  .  .  .  .  .  .  .  .  .  .
+      29    2  1  17 7  2  .  .  .  .  .  .  .  .  .
+      30    2  2  8  3  8  2  .  .  .  .  .  .  .  .
+      31    2  3  6  3  8  2  .  .  .  .  .  .  .  .
+      32    2  4  5  4  7  2  .  .  .  .  .  .  .  .
+      33    2  5  5  4  6  .  .  .  .  .  .  .  .  .
+      34    4  4  5  4  9  .  .  .  .  .  .  .  .  .
+      35    1  4  6  4  4  .  .  .  .  .  .  .  .  .
+      36    4  3  6  4  3  2  .  .  .  .  .  .  .  .
+      37    2  1  2  7  4  4  2  .  .  .  .  .  .  .
+      38    2  2  2  9  5  5  2  .  .  .  .  .  .  .
+      39    2  2  2  10 6  6  .  .  .  .  .  .  .  .
+      40    3  2  1  9  18 .  .  .  .  .  .  .  .  .
+      41    8  4  23 .  .  .  .  .  .  .  .  .  .  .
+      42    1  2  1  2  2  1  1  1  2  .  .  .  .  .
+      43    2  1  4  2  1  4  1  5  1  3  1  2  .  .
+      44    2  1  5  4  4  1  5  1  3  1  2  .  .  .
+      45    1  10 1  1  1  .  .  .  .  .  .  .  .  .
+;
+
+param col : 1  2  3  4  5  6  7  8  9  10 11 12 13 14 :=
+      1     7  1  1  1  1  1  .  .  .  .  .  .  .  .
+      2     2  2  4  1  4  1  5  1  4  1  4  1  2  .
+      3     3  1  4  1  4  1  14 4  1  2  .  .  .  .
+      4     1  1  5  1  2  3  4  1  .  .  .  .  .  .
+      5     3  13 1  10 .  .  .  .  .  .  .  .  .  .
+      6     1  9  4  .  .  .  .  .  .  .  .  .  .  .
+      7     6  7  2  2  .  .  .  .  .  .  .  .  .  .
+      8     8  4  1  4  .  .  .  .  .  .  .  .  .  .
+      9     2  8  3  2  5  3  .  .  .  .  .  .  .  .
+      10    10 1  3  7  2  .  .  .  .  .  .  .  .  .
+      11    8  6  2  8  1  2  .  .  .  .  .  .  .  .
+      12    1  1  2  2  8  1  1  .  .  .  .  .  .  .
+      13    2  1  1  1  2  1  3  1  3  3  1  .  .  .
+      14    2  1  1  1  5  4  2  1  .  .  .  .  .  .
+      15    2  1  1  1  1  7  2  1  .  .  .  .  .  .
+      16    2  1  1  2  9  1  2  1  .  .  .  .  .  .
+      17    4  6  12 1  3  .  .  .  .  .  .  .  .  .
+      18    16 13 3  2  .  .  .  .  .  .  .  .  .  .
+      19    12 21 2  .  .  .  .  .  .  .  .  .  .  .
+      20    2  13 23 .  .  .  .  .  .  .  .  .  .  .
+      21    2  14 19 .  .  .  .  .  .  .  .  .  .  .
+      22    2  14 20 2  .  .  .  .  .  .  .  .  .  .
+      23    2  13 7  2  8  2  .  .  .  .  .  .  .  .
+      24    12 8  1  7  2  .  .  .  .  .  .  .  .  .
+      25    5  1  1  1  2  8  1  5  2  .  .  .  .  .
+      26    2  1  1  1  9  1  1  4  .  .  .  .  .  .
+      27    2  1  1  1  6  1  3  5  .  .  .  .  .  .
+      28    2  2  1  5  6  2  .  .  .  .  .  .  .  .
+      29    2  1  3  1  3  7  3  2  .  .  .  .  .  .
+      30    2  3  2  1  1  2  4  4  2  .  .  .  .  .
+      31    2  2  1  1  2  3  1  8  2  .  .  .  .  .
+      32    9  3  1  7  2  .  .  .  .  .  .  .  .  .
+      33    12 4  1  6  2  .  .  .  .  .  .  .  .  .
+      34    7  4  1  2  5  .  .  .  .  .  .  .  .  .
+      35    2  6  6  5  6  .  .  .  .  .  .  .  .  .
+      36    8  8  6  3  .  .  .  .  .  .  .  .  .  .
+      37    3  10 8  4  2  .  .  .  .  .  .  .  .  .
+      38    5  11 9  5  2  .  .  .  .  .  .  .  .  .
+      39    3  1  12 16 2  .  .  .  .  .  .  .  .  .
+      40    3  1  12 16 .  .  .  .  .  .  .  .  .  .
+      41    5  2  13 21 .  .  .  .  .  .  .  .  .  .
+      42    6  1  3  3  1  1  .  .  .  .  .  .  .  .
+      43    5  1  3  1  3  1  1  2  1  4  1  3  1  3
+      44    5  1  3  1  3  1  4  1  4  1  3  1  3  .
+      45    1  1  1  1  1  1  .  .  .  .  .  .  .  .
+;
+
+end;
Index: deps/glpk/examples/plan.lp
===================================================================
--- deps/glpk/examples/plan.lp	(revision 9)
+++ deps/glpk/examples/plan.lp	(revision 9)
@@ -0,0 +1,39 @@
+\* plan.lp *\
+
+Minimize
+   value: .03 bin1 + .08 bin2 + .17 bin3 + .12 bin4 + .15 bin5 +
+          .21 alum + .38 silicon
+
+Subject To
+   yield:     bin1 +     bin2 +     bin3 +     bin4 +     bin5 +
+              alum +     silicon                                 =  2000
+
+   fe:    .15 bin1 + .04 bin2 + .02 bin3 + .04 bin4 + .02 bin5 +
+          .01 alum + .03 silicon                                 <=   60
+
+   cu:    .03 bin1 + .05 bin2 + .08 bin3 + .02 bin4 + .06 bin5 +
+          .01 alum                                               <=  100
+
+   mn:    .02 bin1 + .04 bin2 + .01 bin3 + .02 bin4 + .02 bin5   <=   40
+
+   mg:    .02 bin1 + .03 bin2                       + .01 bin5   <=   30
+
+   al:    .70 bin1 + .75 bin2 + .80 bin3 + .75 bin4 + .80 bin5 +
+          .97 alum                                               >= 1500
+
+   si1:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
+          .01 alum + .97 silicon                                 >=  250
+
+   si2:   .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 +
+          .01 alum + .97 silicon                                 <=  300
+
+Bounds
+          bin1 <=  200
+          bin2 <= 2500
+   400 <= bin3 <=  800
+   100 <= bin4 <=  700
+          bin5 <= 1500
+
+End
+
+\* eof *\
Index: deps/glpk/examples/plan.mod
===================================================================
--- deps/glpk/examples/plan.mod	(revision 9)
+++ deps/glpk/examples/plan.mod	(revision 9)
@@ -0,0 +1,39 @@
+/* plan.mod */
+
+var bin1, >= 0, <= 200;
+var bin2, >= 0, <= 2500;
+var bin3, >= 400, <= 800;
+var bin4, >= 100, <= 700;
+var bin5, >= 0, <= 1500;
+var alum, >= 0;
+var silicon, >= 0;
+
+minimize
+
+value: .03 * bin1 + .08 * bin2 + .17 * bin3 + .12 * bin4 + .15 * bin5 +
+       .21 * alum + .38 * silicon;
+
+subject to
+
+yield: bin1 + bin2 + bin3 + bin4 + bin5 + alum + silicon = 2000;
+
+fe: .15 * bin1 + .04 * bin2 + .02 * bin3 + .04 * bin4 + .02 * bin5 +
+    .01 * alum + .03 * silicon <= 60;
+
+cu: .03 * bin1 + .05 * bin2 + .08 * bin3 + .02 * bin4 + .06 * bin5 +
+    .01 * alum <= 100;
+
+mn: .02 * bin1 + .04 * bin2 + .01 * bin3 + .02 * bin4 + .02 * bin5
+    <= 40;
+
+mg: .02 * bin1 + .03 * bin2 + .01 * bin5 <= 30;
+
+al: .70 * bin1 + .75 * bin2 + .80 * bin3 + .75 * bin4 + .80 * bin5 +
+    .97 * alum >= 1500;
+
+si: 250 <= .02 * bin1 + .06 * bin2 + .08 * bin3 + .12 * bin4 +
+    .02 * bin5 + .01 * alum + .97 * silicon <= 300;
+
+end;
+
+/* eof */
Index: deps/glpk/examples/plan.mps
===================================================================
--- deps/glpk/examples/plan.mps	(revision 9)
+++ deps/glpk/examples/plan.mps	(revision 9)
@@ -0,0 +1,54 @@
+*000000001111111111222222222233333333334444444444555555555566
+*234567890123456789012345678901234567890123456789012345678901
+NAME          PLAN
+ROWS
+ N  VALUE
+ E  YIELD
+ L  FE
+ L  CU
+ L  MN
+ L  MG
+ G  AL
+ L  SI
+COLUMNS
+    BIN1      VALUE           .03000   YIELD          1.00000
+              FE              .15000   CU              .03000
+              MN              .02000   MG              .02000
+              AL              .70000   SI              .02000
+    BIN2      VALUE           .08000   YIELD          1.00000
+              FE              .04000   CU              .05000
+              MN              .04000   MG              .03000
+              AL              .75000   SI              .06000
+    BIN3      VALUE           .17000   YIELD          1.00000
+              FE              .02000   CU              .08000
+              MN              .01000   AL              .80000
+              SI              .08000
+    BIN4      VALUE           .12000   YIELD          1.00000
+              FE              .04000   CU              .02000
+              MN              .02000   AL              .75000
+              SI              .12000
+    BIN5      VALUE           .15000   YIELD          1.00000
+              FE              .02000   CU              .06000
+              MN              .02000   MG              .01000
+              AL              .80000   SI              .02000
+    ALUM      VALUE           .21000   YIELD          1.00000
+              FE              .01000   CU              .01000
+              AL              .97000   SI              .01000
+    SILICON   VALUE           .38000   YIELD          1.00000
+              FE              .03000   SI              .97000
+RHS
+    RHS1      YIELD       2000.00000   FE            60.00000
+              CU           100.00000   MN            40.00000
+              SI           300.00000
+              MG            30.00000   AL          1500.00000
+RANGES
+    RNG1      SI            50.00000
+BOUNDS
+ UP BND1      BIN1         200.00000
+ UP           BIN2        2500.00000
+ LO           BIN3         400.00000
+ UP           BIN3         800.00000
+ LO           BIN4         100.00000
+ UP           BIN4         700.00000
+ UP           BIN5        1500.00000
+ENDATA
Index: deps/glpk/examples/prod.mod
===================================================================
--- deps/glpk/examples/prod.mod	(revision 9)
+++ deps/glpk/examples/prod.mod	(revision 9)
@@ -0,0 +1,331 @@
+# PROD, a multiperiod production model
+#
+# References:
+# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
+# for Mathematical Programming." Management Science 36 (1990) 519-554.
+
+###  PRODUCTION SETS AND PARAMETERS  ###
+
+set prd 'products';    # Members of the product group
+
+param pt 'production time' {prd} > 0;
+
+                        # Crew-hours to produce 1000 units
+
+param pc 'production cost' {prd} > 0;
+
+                        # Nominal production cost per 1000, used
+                        # to compute inventory and shortage costs
+
+###  TIME PERIOD SETS AND PARAMETERS  ###
+
+param first > 0 integer;
+                        # Index of first production period to be modeled
+
+param last > first integer;
+
+                        # Index of last production period to be modeled
+
+set time 'planning horizon' := first..last;
+
+###  EMPLOYMENT PARAMETERS  ###
+
+param cs 'crew size' > 0 integer;
+
+                        # Workers per crew
+
+param sl 'shift length' > 0;
+
+                        # Regular-time hours per shift
+
+param rtr 'regular time rate' > 0;
+
+                        # Wage per hour for regular-time labor
+
+param otr 'overtime rate' > rtr;
+
+                        # Wage per hour for overtime labor
+
+param iw 'initial workforce' >= 0 integer;
+
+                        # Crews employed at start of first period
+
+param dpp 'days per period' {time} > 0;
+
+                        # Regular working days in a production period
+
+param ol 'overtime limit' {time} >= 0;
+
+                        # Maximum crew-hours of overtime in a period
+
+param cmin 'crew minimum' {time} >= 0;
+
+                        # Lower limit on average employment in a period
+
+param cmax 'crew maximum' {t in time} >= cmin[t];
+
+                        # Upper limit on average employment in a period
+
+param hc 'hiring cost' {time} >= 0;
+
+                        # Penalty cost of hiring a crew
+
+param lc 'layoff cost' {time} >= 0;
+
+                        # Penalty cost of laying off a crew
+
+###  DEMAND PARAMETERS  ###
+
+param dem 'demand' {prd,first..last+1} >= 0;
+
+                        # Requirements (in 1000s)
+                        # to be met from current production and inventory
+
+param pro 'promoted' {prd,first..last+1} logical;
+
+                        # true if product will be the subject
+                        # of a special promotion in the period
+
+###  INVENTORY AND SHORTAGE PARAMETERS  ###
+
+param rir 'regular inventory ratio' >= 0;
+
+                        # Proportion of non-promoted demand
+                        # that must be in inventory the previous period
+
+param pir 'promotional inventory ratio' >= 0;
+
+                        # Proportion of promoted demand
+                        # that must be in inventory the previous period
+
+param life 'inventory lifetime' > 0 integer;
+
+                        # Upper limit on number of periods that
+                        # any product may sit in inventory
+
+param cri 'inventory cost ratio' {prd} > 0;
+
+                        # Inventory cost per 1000 units is
+                        # cri times nominal production cost
+
+param crs 'shortage cost ratio' {prd} > 0;
+
+                        # Shortage cost per 1000 units is
+                        # crs times nominal production cost
+
+param iinv 'initial inventory' {prd} >= 0;
+
+                        # Inventory at start of first period; age unknown
+
+param iil 'initial inventory left' {p in prd, t in time}
+              := iinv[p] less sum {v in first..t} dem[p,v];
+
+                        # Initial inventory still available for allocation
+                        # at end of period t
+
+param minv 'minimum inventory' {p in prd, t in time}
+              := dem[p,t+1] * (if pro[p,t+1] then pir else rir);
+
+                        # Lower limit on inventory at end of period t
+
+###  VARIABLES  ###
+
+var Crews{first-1..last} >= 0;
+
+                        # Average number of crews employed in each period
+
+var Hire{time} >= 0;    # Crews hired from previous to current period
+
+var Layoff{time} >= 0;  # Crews laid off from previous to current period
+
+var Rprd 'regular production' {prd,time} >= 0;
+
+                        # Production using regular-time labor, in 1000s
+
+var Oprd 'overtime production' {prd,time} >= 0;
+
+                        # Production using overtime labor, in 1000s
+
+var Inv 'inventory' {prd,time,1..life} >= 0;
+
+                        # Inv[p,t,a] is the amount of product p that is
+                        # a periods old -- produced in period (t+1)-a --
+                        # and still in storage at the end of period t
+
+var Short 'shortage' {prd,time} >= 0;
+
+                        # Accumulated unsatisfied demand at the end of period t
+
+###  OBJECTIVE  ###
+
+minimize cost:
+
+    sum {t in time} rtr * sl * dpp[t] * cs * Crews[t] +
+    sum {t in time} hc[t] * Hire[t] +
+    sum {t in time} lc[t] * Layoff[t] +
+    sum {t in time, p in prd} otr * cs * pt[p] * Oprd[p,t] +
+    sum {t in time, p in prd, a in 1..life} cri[p] * pc[p] * Inv[p,t,a] +
+    sum {t in time, p in prd} crs[p] * pc[p] * Short[p,t];
+
+                        # Full regular wages for all crews employed, plus
+                        # penalties for hiring and layoffs, plus
+                        # wages for any overtime worked, plus
+                        # inventory and shortage costs
+
+                        # (All other production costs are assumed
+                        # to depend on initial inventory and on demands,
+                        # and so are not included explicitly.)
+
+###  CONSTRAINTS  ###
+
+rlim 'regular-time limit' {t in time}:
+
+    sum {p in prd} pt[p] * Rprd[p,t] <= sl * dpp[t] * Crews[t];
+
+                        # Hours needed to accomplish all regular-time
+                        # production in a period must not exceed
+                        # hours available on all shifts
+
+olim 'overtime limit' {t in time}:
+
+    sum {p in prd} pt[p] * Oprd[p,t] <= ol[t];
+
+                        # Hours needed to accomplish all overtime
+                        # production in a period must not exceed
+                        # the specified overtime limit
+
+empl0 'initial crew level':  Crews[first-1] = iw;
+
+                        # Use given initial workforce
+
+empl 'crew levels' {t in time}:  Crews[t] = Crews[t-1] + Hire[t] - Layoff[t];
+
+                        # Workforce changes by hiring or layoffs
+
+emplbnd 'crew limits' {t in time}:  cmin[t] <= Crews[t] <= cmax[t];
+
+                        # Workforce must remain within specified bounds
+
+dreq1 'first demand requirement' {p in prd}:
+
+    Rprd[p,first] + Oprd[p,first] + Short[p,first]
+                             - Inv[p,first,1] = dem[p,first] less iinv[p];
+
+dreq 'demand requirements' {p in prd, t in first+1..last}:
+
+    Rprd[p,t] + Oprd[p,t] + Short[p,t] - Short[p,t-1]
+                          + sum {a in 1..life} (Inv[p,t-1,a] - Inv[p,t,a])
+                                                  = dem[p,t] less iil[p,t-1];
+
+                        # Production plus increase in shortage plus
+                        # decrease in inventory must equal demand
+
+ireq 'inventory requirements' {p in prd, t in time}:
+
+    sum {a in 1..life} Inv[p,t,a] + iil[p,t] >= minv[p,t];
+
+                        # Inventory in storage at end of period t
+                        # must meet specified minimum
+
+izero 'impossible inventories' {p in prd, v in 1..life-1, a in v+1..life}:
+
+    Inv[p,first+v-1,a] = 0;
+
+                        # In the vth period (starting from first)
+                        # no inventory may be more than v periods old
+                        # (initial inventories are handled separately)
+
+ilim1 'new-inventory limits' {p in prd, t in time}:
+
+    Inv[p,t,1] <= Rprd[p,t] + Oprd[p,t];
+
+                        # New inventory cannot exceed
+                        # production in the most recent period
+
+ilim 'inventory limits' {p in prd, t in first+1..last, a in 2..life}:
+
+    Inv[p,t,a] <= Inv[p,t-1,a-1];
+
+                        # Inventory left from period (t+1)-p
+                        # can only decrease as time goes on
+
+###  DATA  ###
+
+data;
+
+set prd := 18REG 24REG 24PRO ;
+
+param first :=  1 ;
+param last  := 13 ;
+param life  :=  2 ;
+
+param cs := 18 ;
+param sl :=  8 ;
+param iw :=  8 ;
+
+param rtr := 16.00 ;
+param otr := 43.85 ;
+param rir :=  0.75 ;
+param pir :=  0.80 ;
+
+param :         pt       pc        cri       crs      iinv   :=
+
+  18REG      1.194     2304.     0.015     1.100      82.0
+  24REG      1.509     2920.     0.015     1.100     792.2
+  24PRO      1.509     2910.     0.015     1.100       0.0   ;
+
+param :     dpp        ol      cmin      cmax        hc        lc   :=
+
+  1        19.5      96.0       0.0       8.0      7500      7500
+  2        19.0      96.0       0.0       8.0      7500      7500
+  3        20.0      96.0       0.0       8.0      7500      7500
+  4        19.0      96.0       0.0       8.0      7500      7500
+  5        19.5      96.0       0.0       8.0     15000     15000
+  6        19.0      96.0       0.0       8.0     15000     15000
+  7        19.0      96.0       0.0       8.0     15000     15000
+  8        20.0      96.0       0.0       8.0     15000     15000
+  9        19.0      96.0       0.0       8.0     15000     15000
+ 10        20.0      96.0       0.0       8.0     15000     15000
+ 11        20.0      96.0       0.0       8.0      7500      7500
+ 12        18.0      96.0       0.0       8.0      7500      7500
+ 13        18.0      96.0       0.0       8.0      7500      7500   ;
+
+param dem (tr) :
+
+          18REG     24REG     24PRO   :=
+
+  1        63.8    1212.0       0.0
+  2        76.0     306.2       0.0
+  3        88.4     319.0       0.0
+  4       913.8     208.4       0.0
+  5       115.0     298.0       0.0
+  6       133.8     328.2       0.0
+  7        79.6     959.6       0.0
+  8       111.0     257.6       0.0
+  9       121.6     335.6       0.0
+ 10       470.0     118.0    1102.0
+ 11        78.4     284.8       0.0
+ 12        99.4     970.0       0.0
+ 13       140.4     343.8       0.0
+ 14        63.8    1212.0       0.0   ;
+
+param pro (tr) :
+
+          18REG     24REG     24PRO   :=
+
+  1           0         1         0
+  2           0         0         0
+  3           0         0         0
+  4           1         0         0
+  5           0         0         0
+  6           0         0         0
+  7           0         1         0
+  8           0         0         0
+  9           0         0         0
+ 10           1         0         1
+ 11           0         0         0
+ 12           0         0         0
+ 13           0         1         0
+ 14           0         1         0   ;
+
+end;
Index: deps/glpk/examples/qfit.mod
===================================================================
--- deps/glpk/examples/qfit.mod	(revision 9)
+++ deps/glpk/examples/qfit.mod	(revision 9)
@@ -0,0 +1,49 @@
+/*Quadratic Curve Fitting Solution
+
+  Find a plausable quadratic fit to a sample of points
+
+  Nigel_Galloway@operamail.com
+  February 1st., 2009
+*/
+set Sample;
+param Sx {z in Sample};
+param Sy {z in Sample};
+
+var a;
+var b;
+var c;
+
+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];
+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];
+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];
+
+solve;
+
+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);
+
+data;
+
+param:
+Sample:   Sx    Sy :=
+  1         0    1
+  2       0.5  0.9
+  3         1  0.7
+  4       1.5  1.5
+  5       1.9    2
+  6       2.5  2.4
+  7         3  3.2
+  8       3.5    2
+  9         4  2.7
+ 10       4.5  3.5
+ 11         5    1
+ 12       5.5    4
+ 13         6  3.6
+ 14       6.6  2.7
+ 15         7  5.7
+ 16       7.6  4.6
+ 17       8.5    6
+ 18         9  6.8
+ 19        10  7.3
+;
+
+end;
Index: deps/glpk/examples/queens.mod
===================================================================
--- deps/glpk/examples/queens.mod	(revision 9)
+++ deps/glpk/examples/queens.mod	(revision 9)
@@ -0,0 +1,41 @@
+/* QUEENS, a classic combinatorial optimization problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Queens Problem is to place as many queens as possible on the 8x8
+   (or more generally, nxn) chess board in a way that they do not fight
+   each other. This problem is probably as old as the chess game itself,
+   and thus its origin is not known, but it is known that Gauss studied
+   this problem. */
+
+param n, integer, > 0, default 8;
+/* size of the chess board */
+
+var x{1..n, 1..n}, binary;
+/* x[i,j] = 1 means that a queen is placed in square [i,j] */
+
+s.t. a{i in 1..n}: sum{j in 1..n} x[i,j] <= 1;
+/* at most one queen can be placed in each row */
+
+s.t. b{j in 1..n}: sum{i in 1..n} x[i,j] <= 1;
+/* at most one queen can be placed in each column */
+
+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;
+/* at most one queen can be placed in each "\"-diagonal */
+
+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;
+/* at most one queen can be placed in each "/"-diagonal */
+
+maximize obj: sum{i in 1..n, j in 1..n} x[i,j];
+/* objective is to place as many queens as possible */
+
+/* solve the problem */
+solve;
+
+/* and print its optimal solution */
+for {i in 1..n}
+{  for {j in 1..n} printf " %s", if x[i,j] then "Q" else ".";
+   printf("\n");
+}
+
+end;
Index: deps/glpk/examples/samp1.mps
===================================================================
--- deps/glpk/examples/samp1.mps	(revision 9)
+++ deps/glpk/examples/samp1.mps	(revision 9)
@@ -0,0 +1,29 @@
+NAME          SAMP1
+ROWS
+ N  Z
+ G  R1
+ G  R2
+ G  R3
+COLUMNS
+    X1        R1                2.0    R2                 1.0
+    X1        R3                5.0    Z                  3.0
+    MARK0001  'MARKER'                 'INTORG'
+    X2        R1               -1.0    R2                -1.0
+    X2        R3                3.0    Z                  7.0
+    X3        R1                1.0    R2                -6.0
+    X3        Z                -1.0
+    MARK0002  'MARKER'                 'INTEND'
+    X4        R1               -1.0    R2                 4.0
+    X4        R3                1.0    Z                  1.0
+RHS
+    RHS1      R1                1.0
+    RHS1      R2                8.0
+    RHS1      R3                5.0
+BOUNDS
+ UP BND1      X1                4.0
+ LO BND1      X2                2.0
+ UP BND1      X2                5.0
+ UP BND1      X3                1.0
+ LO BND1      X4                3.0
+ UP BND1      X4                8.0
+ENDATA
Index: deps/glpk/examples/samp2.mps
===================================================================
--- deps/glpk/examples/samp2.mps	(revision 9)
+++ deps/glpk/examples/samp2.mps	(revision 9)
@@ -0,0 +1,27 @@
+NAME          SAMP2
+ROWS
+ N  Z
+ G  R1
+ G  R2
+ G  R3
+COLUMNS
+    X1        R1                2.0    R2                 1.0
+    X1        R3                5.0    Z                  3.0
+    X2        R1               -1.0    R2                -1.0
+    X2        R3                3.0    Z                  7.0
+    X3        R1                1.0    R2                -6.0
+    X3        Z                -1.0
+    X4        R1               -1.0    R2                 4.0
+    X4        R3                1.0    Z                  1.0
+RHS
+    RHS1      R1                1.0
+    RHS1      R2                8.0
+    RHS1      R3                5.0
+BOUNDS
+ UP BND1      X1                4.0
+ LO BND1      X2                2.0
+ UI BND1      X2                5.0
+ BV BND1      X3
+ LO BND1      X4                3.0
+ UP BND1      X4                8.0
+ENDATA
Index: deps/glpk/examples/sample.asn
===================================================================
--- deps/glpk/examples/sample.asn	(revision 9)
+++ deps/glpk/examples/sample.asn	(revision 9)
@@ -0,0 +1,40 @@
+c sample.asn
+c
+c This is an example of the assignment problem data
+c in DIMACS format.
+c
+p asn 17 22
+c
+n 1
+n 2
+n 3
+n 4
+n 5
+n 6
+n 7
+n 8
+c
+a 1  9 13
+a 1 10 21
+a 1 12 20
+a 2 10 12
+a 2 12  8
+a 2 13 26
+a 3 11 22
+a 3 13 11
+a 4  9 12
+a 4 12 36
+a 4 14 25
+a 5 11 41
+a 5 12 40
+a 5 13 11
+a 5 14  4
+a 5 15  8
+a 5 16 35
+a 5 17 32
+a 6  9 13
+a 7 10 19
+a 8 10 39
+a 8 11 15
+c
+c eof
Index: deps/glpk/examples/sample.c
===================================================================
--- deps/glpk/examples/sample.c	(revision 9)
+++ deps/glpk/examples/sample.c	(revision 9)
@@ -0,0 +1,52 @@
+/* sample.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *lp;
+      int ia[1+1000], ja[1+1000];
+      double ar[1+1000], z, x1, x2, x3;
+s1:   lp = glp_create_prob();
+s2:   glp_set_prob_name(lp, "sample");
+s3:   glp_set_obj_dir(lp, GLP_MAX);
+s4:   glp_add_rows(lp, 3);
+s5:   glp_set_row_name(lp, 1, "p");
+s6:   glp_set_row_bnds(lp, 1, GLP_UP, 0.0, 100.0);
+s7:   glp_set_row_name(lp, 2, "q");
+s8:   glp_set_row_bnds(lp, 2, GLP_UP, 0.0, 600.0);
+s9:   glp_set_row_name(lp, 3, "r");
+s10:  glp_set_row_bnds(lp, 3, GLP_UP, 0.0, 300.0);
+s11:  glp_add_cols(lp, 3);
+s12:  glp_set_col_name(lp, 1, "x1");
+s13:  glp_set_col_bnds(lp, 1, GLP_LO, 0.0, 0.0);
+s14:  glp_set_obj_coef(lp, 1, 10.0);
+s15:  glp_set_col_name(lp, 2, "x2");
+s16:  glp_set_col_bnds(lp, 2, GLP_LO, 0.0, 0.0);
+s17:  glp_set_obj_coef(lp, 2, 6.0);
+s18:  glp_set_col_name(lp, 3, "x3");
+s19:  glp_set_col_bnds(lp, 3, GLP_LO, 0.0, 0.0);
+s20:  glp_set_obj_coef(lp, 3, 4.0);
+s21:  ia[1] = 1, ja[1] = 1, ar[1] =  1.0; /* a[1,1] =  1 */
+s22:  ia[2] = 1, ja[2] = 2, ar[2] =  1.0; /* a[1,2] =  1 */
+s23:  ia[3] = 1, ja[3] = 3, ar[3] =  1.0; /* a[1,3] =  1 */
+s24:  ia[4] = 2, ja[4] = 1, ar[4] = 10.0; /* a[2,1] = 10 */
+s25:  ia[5] = 3, ja[5] = 1, ar[5] =  2.0; /* a[3,1] =  2 */
+s26:  ia[6] = 2, ja[6] = 2, ar[6] =  4.0; /* a[2,2] =  4 */
+s27:  ia[7] = 3, ja[7] = 2, ar[7] =  2.0; /* a[3,2] =  2 */
+s28:  ia[8] = 2, ja[8] = 3, ar[8] =  5.0; /* a[2,3] =  5 */
+s29:  ia[9] = 3, ja[9] = 3, ar[9] =  6.0; /* a[3,3] =  6 */
+s30:  glp_load_matrix(lp, 9, ia, ja, ar);
+s31:  glp_simplex(lp, NULL);
+s32:  z = glp_get_obj_val(lp);
+s33:  x1 = glp_get_col_prim(lp, 1);
+s34:  x2 = glp_get_col_prim(lp, 2);
+s35:  x3 = glp_get_col_prim(lp, 3);
+s36:  printf("\nz = %g; x1 = %g; x2 = %g; x3 = %g\n",
+         z, x1, x2, x3);
+s37:  glp_delete_prob(lp);
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/examples/sample.clq
===================================================================
--- deps/glpk/examples/sample.clq	(revision 9)
+++ deps/glpk/examples/sample.clq	(revision 9)
@@ -0,0 +1,30 @@
+c sample.clq
+c
+c This is an example of the Maximum Weight Clique
+c Problem in DIMACS clique/coloring format.
+c
+p edge 8 16
+n 1 3
+n 2 4
+n 3 8
+n 5 5
+n 6 2
+n 8 3
+e 1 4
+e 1 5
+e 1 6
+e 1 8
+e 2 3
+e 2 6
+e 2 7
+e 2 8
+e 3 4
+e 3 6
+e 3 7
+e 4 5
+e 4 8
+e 5 7
+e 5 8
+e 6 7
+c
+c eof
Index: deps/glpk/examples/sample.cnf
===================================================================
--- deps/glpk/examples/sample.cnf	(revision 9)
+++ deps/glpk/examples/sample.cnf	(revision 9)
@@ -0,0 +1,12 @@
+c sample.cnf
+c
+c This is an example of the CNF-SAT problem data
+c in DIMACS format.
+c
+p cnf 4 3
+1 2 0
+-4 3
+-2 0
+-1 4 0
+c
+c eof
Index: deps/glpk/examples/sample.col
===================================================================
--- deps/glpk/examples/sample.col	(revision 9)
+++ deps/glpk/examples/sample.col	(revision 9)
@@ -0,0 +1,30 @@
+c sample.col
+c
+c This is an example of the vertex coloring problem data
+c in DIMACS format.
+c
+p edge 10 21
+c
+e 1 2
+e 1 6
+e 1 7
+e 1 10
+e 2 3
+e 2 7
+e 2 8
+e 3 4
+e 3 8
+e 4 5
+e 4 8
+e 4 9
+e 5 6
+e 5 9
+e 5 10
+e 6 10
+e 7 8
+e 7 10
+e 8 9
+e 8 10
+e 9 10
+c
+c eof
Index: deps/glpk/examples/sample.max
===================================================================
--- deps/glpk/examples/sample.max	(revision 9)
+++ deps/glpk/examples/sample.max	(revision 9)
@@ -0,0 +1,26 @@
+c sample.max
+c
+c This is an example of the maximum flow problem data
+c in DIMACS format.
+c
+p max 9 14
+c
+n 1 s
+n 9 t
+c
+a 1 2 14
+a 1 4 23
+a 2 3 10
+a 2 4  9
+a 3 5 12
+a 3 8 18
+a 4 5 26
+a 5 2 11
+a 5 6 25
+a 5 7  4
+a 6 7  7
+a 6 8  8
+a 7 9 15
+a 8 9 20
+c
+c eof
Index: deps/glpk/examples/sample.min
===================================================================
--- deps/glpk/examples/sample.min	(revision 9)
+++ deps/glpk/examples/sample.min	(revision 9)
@@ -0,0 +1,26 @@
+c sample.min
+c
+c This is an example of the minimum cost flow problem data
+c in DIMACS format.
+c
+p min 9 14
+c
+n 1 20
+n 9 -20
+c
+a 1 2 0 14 0
+a 1 4 0 23 0
+a 2 3 0 10 2
+a 2 4 0  9 3
+a 3 5 2 12 1
+a 3 8 0 18 0
+a 4 5 0 26 0
+a 5 2 0 11 1
+a 5 6 0 25 5
+a 5 7 0  4 7
+a 6 7 0  7 0
+a 6 8 4  8 0
+a 7 9 0 15 3
+a 8 9 0 20 9
+c
+c eof
Index: deps/glpk/examples/sat.mod
===================================================================
--- deps/glpk/examples/sat.mod	(revision 9)
+++ deps/glpk/examples/sat.mod	(revision 9)
@@ -0,0 +1,201 @@
+/* SAT, Satisfiability Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+param m, integer, > 0;
+/* number of clauses */
+
+param n, integer, > 0;
+/* number of variables */
+
+set C{1..m};
+/* clauses; each clause C[i], i = 1, ..., m, is disjunction of some
+   variables or their negations; in the data section each clause is
+   coded as a set of indices of corresponding variables, where negative
+   indices mean negation; for example, the clause (x3 or not x7 or x11)
+   is coded as the set { 3, -7, 11 } */
+
+var x{1..n}, binary;
+/* main variables */
+
+/* To solve the satisfiability problem means to determine all variables
+   x[j] such that conjunction of all clauses C[1] and ... and C[m] takes
+   on the value true, i.e. all clauses are satisfied.
+
+   Let the clause C[i] be (t or t' or ... or t''), where t, t', ..., t''
+   are either variables or their negations. The condition of satisfying
+   C[i] can be most naturally written as:
+
+      t + t' + ... + t'' >= 1,                                       (1)
+
+   where t, t', t'' have to be replaced by either x[j] or (1 - x[j]).
+   The formulation (1) leads to the mip problem with no objective, i.e.
+   to a feasibility problem.
+
+   Another, more practical way is to write the condition for C[i] as:
+
+      t + t' + ... + t'' + y[i] >= 1,                                (2)
+
+   where y[i] is an auxiliary binary variable, and minimize the sum of
+   y[i]. If the sum is zero, all y[i] are also zero, and therefore all
+   clauses are satisfied. If the sum is minimal but non-zero, its value
+   shows the number of clauses which cannot be satisfied. */
+
+var y{1..m}, binary, >= 0;
+/* auxiliary variables */
+
+s.t. c{i in 1..m}:
+      sum{j in C[i]} (if j > 0 then x[j] else (1 - x[-j])) + y[i] >= 1;
+/* the condition (2) */
+
+minimize unsat: sum{i in 1..m} y[i];
+/* number of unsatisfied clauses */
+
+data;
+
+/* These data correspond to the instance hole6 (pigeon hole problem for
+   6 holes) from SATLIB, the Satisfiability Library, which is part of
+   the collection at the Forschungsinstitut fuer anwendungsorientierte
+   Wissensverarbeitung in Ulm Germany */
+
+/* The optimal solution is 1 (one clause cannot be satisfied) */
+
+param m := 133;
+
+param n := 42;
+
+set C[1] := -1 -7;
+set C[2] := -1 -13;
+set C[3] := -1 -19;
+set C[4] := -1 -25;
+set C[5] := -1 -31;
+set C[6] := -1 -37;
+set C[7] := -7 -13;
+set C[8] := -7 -19;
+set C[9] := -7 -25;
+set C[10] := -7 -31;
+set C[11] := -7 -37;
+set C[12] := -13 -19;
+set C[13] := -13 -25;
+set C[14] := -13 -31;
+set C[15] := -13 -37;
+set C[16] := -19 -25;
+set C[17] := -19 -31;
+set C[18] := -19 -37;
+set C[19] := -25 -31;
+set C[20] := -25 -37;
+set C[21] := -31 -37;
+set C[22] := -2 -8;
+set C[23] := -2 -14;
+set C[24] := -2 -20;
+set C[25] := -2 -26;
+set C[26] := -2 -32;
+set C[27] := -2 -38;
+set C[28] := -8 -14;
+set C[29] := -8 -20;
+set C[30] := -8 -26;
+set C[31] := -8 -32;
+set C[32] := -8 -38;
+set C[33] := -14 -20;
+set C[34] := -14 -26;
+set C[35] := -14 -32;
+set C[36] := -14 -38;
+set C[37] := -20 -26;
+set C[38] := -20 -32;
+set C[39] := -20 -38;
+set C[40] := -26 -32;
+set C[41] := -26 -38;
+set C[42] := -32 -38;
+set C[43] := -3 -9;
+set C[44] := -3 -15;
+set C[45] := -3 -21;
+set C[46] := -3 -27;
+set C[47] := -3 -33;
+set C[48] := -3 -39;
+set C[49] := -9 -15;
+set C[50] := -9 -21;
+set C[51] := -9 -27;
+set C[52] := -9 -33;
+set C[53] := -9 -39;
+set C[54] := -15 -21;
+set C[55] := -15 -27;
+set C[56] := -15 -33;
+set C[57] := -15 -39;
+set C[58] := -21 -27;
+set C[59] := -21 -33;
+set C[60] := -21 -39;
+set C[61] := -27 -33;
+set C[62] := -27 -39;
+set C[63] := -33 -39;
+set C[64] := -4 -10;
+set C[65] := -4 -16;
+set C[66] := -4 -22;
+set C[67] := -4 -28;
+set C[68] := -4 -34;
+set C[69] := -4 -40;
+set C[70] := -10 -16;
+set C[71] := -10 -22;
+set C[72] := -10 -28;
+set C[73] := -10 -34;
+set C[74] := -10 -40;
+set C[75] := -16 -22;
+set C[76] := -16 -28;
+set C[77] := -16 -34;
+set C[78] := -16 -40;
+set C[79] := -22 -28;
+set C[80] := -22 -34;
+set C[81] := -22 -40;
+set C[82] := -28 -34;
+set C[83] := -28 -40;
+set C[84] := -34 -40;
+set C[85] := -5 -11;
+set C[86] := -5 -17;
+set C[87] := -5 -23;
+set C[88] := -5 -29;
+set C[89] := -5 -35;
+set C[90] := -5 -41;
+set C[91] := -11 -17;
+set C[92] := -11 -23;
+set C[93] := -11 -29;
+set C[94] := -11 -35;
+set C[95] := -11 -41;
+set C[96] := -17 -23;
+set C[97] := -17 -29;
+set C[98] := -17 -35;
+set C[99] := -17 -41;
+set C[100] := -23 -29;
+set C[101] := -23 -35;
+set C[102] := -23 -41;
+set C[103] := -29 -35;
+set C[104] := -29 -41;
+set C[105] := -35 -41;
+set C[106] := -6 -12;
+set C[107] := -6 -18;
+set C[108] := -6 -24;
+set C[109] := -6 -30;
+set C[110] := -6 -36;
+set C[111] := -6 -42;
+set C[112] := -12 -18;
+set C[113] := -12 -24;
+set C[114] := -12 -30;
+set C[115] := -12 -36;
+set C[116] := -12 -42;
+set C[117] := -18 -24;
+set C[118] := -18 -30;
+set C[119] := -18 -36;
+set C[120] := -18 -42;
+set C[121] := -24 -30;
+set C[122] := -24 -36;
+set C[123] := -24 -42;
+set C[124] := -30 -36;
+set C[125] := -30 -42;
+set C[126] := -36 -42;
+set C[127] := 6 5 4 3 2 1;
+set C[128] := 12 11 10 9 8 7;
+set C[129] := 18 17 16 15 14 13;
+set C[130] := 24 23 22 21 20 19;
+set C[131] := 30 29 28 27 26 25;
+set C[132] := 36 35 34 33 32 31;
+set C[133] := 42 41 40 39 38 37;
+
+end;
Index: deps/glpk/examples/shiftcover.mod
===================================================================
--- deps/glpk/examples/shiftcover.mod	(revision 9)
+++ deps/glpk/examples/shiftcover.mod	(revision 9)
@@ -0,0 +1,244 @@
+/* File: shiftcover.mod */
+
+/* WORKFORCE SHIFT COVERAGE assignment problem */
+
+/* Written by Larry D'Agostino <larrydag -at- sbcglobal -dot- com>
+     
+     Maximize Productivity with Industrial Engineer and Operations Research Tools
+     http://industrialengineertools.blogspot.com
+
+
+/* The WORKFORCE SHIFT COVERAGE is an assigment problem that determines
+   the schedule of crew given available time and shifts.  
+   
+   The objective is to cover the available time given hourly demand with the minimum 
+    number of crew members.
+   
+    This is a set covering problem that is very common among finding crew
+     and shift allocations.  Notice in the data section the workforce shift allocation
+     per day of the week.*/
+
+
+/* ----- Model PARAMTERS and SETS -----*/
+
+param numhrs;
+/* number of hours of operations in a given day */
+
+param dys;
+/* number of days in a week */
+
+set S;
+/* set of crew shifts */
+
+set H := 1..numhrs;
+/* set of hours of a day*/
+
+set D;
+/* set of days of a week*/
+
+param dmnd{h in H, d in D};
+/* demand for crew members given h hour and d day */
+
+param shifts{d in D, h in H, s in S};
+/* shifts to assign to crew members given d day, h hour, and s shift schedule
+
+/*----- Model VARIABLES -----*/
+
+var crew{s in S}, integer, >=0;
+/*  number of crew assigned to shift S */
+
+
+/*----- Model CONSTRAINTS -----*/
+
+s.t. Coverage{h in H, d in D}: sum{s in S} crew[s]*shifts[d,h,s] >= dmnd[h,d];
+/* number of crew to cover with a shift  given hourly demand and day */
+
+
+/*----- Model OBJECTIVE -----*/
+
+minimize obj: sum{s in S} crew[s];
+/* minimize number of crew to cover demand*/
+
+solve;
+display crew;
+
+printf "\n";
+printf "Total Crew: %3d\n\n", sum{s in S} crew[s];
+
+
+
+printf "\n\n";
+printf "Weekly Crew Schedule\n\n";
+printf "Hour ";
+printf{d in D} "  %s  ", d;
+printf "\n";
+for {h in H} {
+  printf " %2s  ",h;
+  printf{d in D} " %3d   ", sum{s in S} crew[s]*shifts[d,h,s];
+  printf "\n";
+}
+printf"\n";
+
+
+
+data;
+
+param numhrs := 16;
+
+set D := SUN, MON, TUE, WED, THU, FRI, SAT;
+
+set S := Sh1, Sh2, Sh3, Sh4, Sh5, Sh6, Sh7, Sh8, Sh9;
+
+param dmnd :   SUN  MON     TUE     WED     THU     FRI     SAT :=
+1               0   3       3       4       3       2       0
+2               0   14      14      16      14      12      12
+3               0   24      24      27      24      20      15
+4               0   28      28      32      28      23      15
+5               0   33      33      37      33      24      16
+6               0   34      34      38      34      24      15
+7               0   35      35      39      35      25      11
+8               0   35      35      40      35      27      0
+9               0   34      34      39      34      25      0
+10              0   31      31      35      31      24      0
+11              2   24      24      27      24      25      0
+12              3   19      19      21      19      21      0
+13              2   24      24      27      24      13      0
+14              2   16      16      18      16      0       0
+15              0   7       7       7       7       0       0
+16              0   5       5       5       5       0       0;
+
+
+param shifts := 
+['SUN',*,*]:
+                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
+1                   0    0    0    0    0    0    0    0    0
+2                   0    0    0    0    0    0    0    0    0
+3                   0    0    0    0    0    0    0    0    0
+4                   0    0    0    0    0    0    0    0    0
+5                   0    0    0    0    0    0    0    0    0
+6                   0    0    0    0    0    0    0    0    0
+7                   0    0    0    0    0    0    0    0    0
+8                   0    0    0    0    0    0    0    0    0
+9                   0    0    0    0    0    0    0    0    0
+10                  0    0    0    0    0    0    0    0    0
+11                  0    0    0    0    0    0    0    0    1
+12                  0    0    0    0    0    0    0    0    1
+13                  0    0    0    0    0    0    0    0    1
+14                  0    0    0    0    0    0    0    0    1
+15                  0    0    0    0    0    0    0    0    0
+16                  0    0    0    0    0    0    0    0    0
+
+
+['MON',*,*]:
+                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
+1                   1    0    0    0    0    0    0    0    0
+2                   1    1    0    0    0    0    0    0    0
+3                   1    1    1    0    0    0    0    0    0
+4                   1    1    1    1    0    0    0    0    0
+5                   0    1    1    1    1    0    0    0    0
+6                   1    0    1    1    1    1    0    0    1
+7                   1    1    0    1    1    1    1    0    1
+8                   1    1    1    0    1    1    1    1    1
+9                   1    1    1    1    0    1    1    1    1
+10                  0    1    1    1    1    0    1    1    1
+11                  0    0    1    1    1    1    0    1    0
+12                  0    0    0    1    1    1    1    0    1
+13                  0    0    0    0    1    1    1    1    1
+14                  0    0    0    0    0    1    1    1    1
+15                  0    0    0    0    0    0    1    1    1
+16                  0    0    0    0    0    0    0    1    1
+
+['TUE',*,*]:
+                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
+1                   1    0    0    0    0    0    0    0    0
+2                   1    1    0    0    0    0    0    0    0
+3                   1    1    1    0    0    0    0    0    0
+4                   1    1    1    1    0    0    0    0    0
+5                   0    1    1    1    1    0    0    0    0
+6                   1    0    1    1    1    1    0    0    1
+7                   1    1    0    1    1    1    1    0    1
+8                   1    1    1    0    1    1    1    1    1
+9                   1    1    1    1    0    1    1    1    1
+10                  0    1    1    1    1    0    1    1    1
+11                  0    0    1    1    1    1    0    1    0
+12                  0    0    0    1    1    1    1    0    1
+13                  0    0    0    0    1    1    1    1    1
+14                  0    0    0    0    0    1    1    1    1
+15                  0    0    0    0    0    0    1    1    1
+16                  0    0    0    0    0    0    0    1    1
+
+['WED',*,*]:
+                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
+1                   1    0    0    0    0    0    0    0    0
+2                   1    1    0    0    0    0    0    0    0
+3                   1    1    1    0    0    0    0    0    0
+4                   1    1    1    1    0    0    0    0    0
+5                   0    1    1    1    1    0    0    0    0
+6                   1    0    1    1    1    1    0    0    1
+7                   1    1    0    1    1    1    1    0    1
+8                   1    1    1    0    1    1    1    1    1
+9                   1    1    1    1    0    1    1    1    1
+10                  0    1    1    1    1    0    1    1    1
+11                  0    0    1    1    1    1    0    1    0
+12                  0    0    0    1    1    1    1    0    1
+13                  0    0    0    0    1    1    1    1    1
+14                  0    0    0    0    0    1    1    1    1
+15                  0    0    0    0    0    0    1    1    1
+16                  0    0    0    0    0    0    0    1    1
+
+['THU',*,*]:
+                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
+1                   1    0    0    0    0    0    0    0    0
+2                   1    1    0    0    0    0    0    0    0
+3                   1    1    1    0    0    0    0    0    0
+4                   1    1    1    1    0    0    0    0    0
+5                   0    1    1    1    1    0    0    0    0
+6                   1    0    1    1    1    1    0    0    0
+7                   1    1    0    1    1    1    1    0    0
+8                   1    1    1    0    1    1    1    1    0
+9                   1    1    1    1    0    1    1    1    0
+10                  0    1    1    1    1    0    1    1    0
+11                  0    0    1    1    1    1    0    1    0
+12                  0    0    0    1    1    1    1    0    0
+13                  0    0    0    0    1    1    1    1    0
+14                  0    0    0    0    0    1    1    1    0
+15                  0    0    0    0    0    0    1    1    0
+16                  0    0    0    0    0    0    0    1    0
+
+['FRI',*,*]:
+                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
+1                   1    0    0    0    0    0    0    0    0
+2                   1    1    0    0    0    0    0    0    0
+3                   1    1    1    0    0    0    0    0    0
+4                   1    1    1    1    0    0    0    0    0
+5                   0    1    1    1    1    0    0    0    0
+6                   1    0    1    1    1    1    0    0    0
+7                   1    1    0    1    1    1    1    0    0
+8                   1    1    1    0    1    1    1    1    0
+9                   1    1    1    1    0    1    1    1    0
+10                  0    1    1    1    1    0    1    1    0
+11                  0    0    1    1    1    1    0    1    0
+12                  0    0    0    1    1    1    1    0    0
+13                  0    0    0    0    1    1    1    1    0
+14                  0    0    0    0    0    1    1    1    0
+15                  0    0    0    0    0    0    1    1    0
+16                  0    0    0    0    0    0    0    1    0
+
+['SAT',*,*]:
+                   Sh1  Sh2  Sh3  Sh4  Sh5  Sh6  Sh7  Sh8  Sh9 :=
+1                   0    0    0    0    0    0    0    0    0
+2                   0    0    0    0    0    0    0    0    1
+3                   0    0    0    0    0    0    0    0    1
+4                   0    0    0    0    0    0    0    0    1
+5                   0    0    0    0    0    0    0    0    1
+6                   0    0    0    0    0    0    0    0    1
+7                   0    0    0    0    0    0    0    0    1
+8                   0    0    0    0    0    0    0    0    0
+9                   0    0    0    0    0    0    0    0    0
+10                  0    0    0    0    0    0    0    0    0
+11                  0    0    0    0    0    0    0    0    0
+12                  0    0    0    0    0    0    0    0    0
+13                  0    0    0    0    0    0    0    0    0
+14                  0    0    0    0    0    0    0    0    0
+15                  0    0    0    0    0    0    0    0    0
+16                  0    0    0    0    0    0    0    0    0;
Index: deps/glpk/examples/shikaku.mod
===================================================================
--- deps/glpk/examples/shikaku.mod	(revision 9)
+++ deps/glpk/examples/shikaku.mod	(revision 9)
@@ -0,0 +1,107 @@
+/* A solver for the Japanese number-puzzle Shikaku
+ * http://en.wikipedia.org/wiki/Shikaku
+ *
+ * Sebastian Nowozin <nowozin@gmail.com>, 27th January 2009
+ */
+
+param ndim := 10;
+set rows := 1..ndim;
+set rows1 := 1..(ndim+1);
+set cols := 1..ndim;
+set cols1 := 1..(ndim+1);
+param givens{rows, cols}, integer, >= 0, default 0;
+
+/* Set of vertices as (row,col) coordinates */
+set V := { (i,j) in { rows, cols }: givens[i,j] != 0 };
+
+/* Set of all feasible boxes of the right size: only this boxes are possible.
+ * The box contains (i,j) and ranges from (k,l) to (m,n)
+ */
+set B := { (i,j,k,l,m,n) in { V, rows, cols, rows1, cols1 }:
+    i >= k and i < m and j >= l and j < n and   /* Contains (i,j) */
+    ((m-k)*(n-l)) = givens[i,j] and /* Right size */
+    card({ (s,t) in V: s >= k and s < m and t >= l and t < n }) = 1
+        /* Contains only (i,j), no other number */
+};
+
+var x{B}, binary;
+
+/* Cover each square exactly once */
+s.t. cover_once{ (s,t) in { rows, cols } }:
+    sum{(i,j,k,l,m,n) in B: s >= k and s < m and t >= l and t < n}
+        x[i,j,k,l,m,n] = 1;
+
+minimize cost: 0;
+
+solve;
+
+/* Output solution graphically */
+printf "\nSolution:\n";
+for { row in rows1 } {
+    for { col in cols1 } {
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+                col >= l and col <= n and (row = k or row = m) and
+                x[i,j,k,l,m,n] = 1}) > 0 and
+            card({(i,j,k,l,m,n) in B:
+                row >= k and row <= m and (col = l or col = n) and
+                x[i,j,k,l,m,n] = 1}) > 0} "+";
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+                col >= l and col <= n and (row = k or row = m) and
+                x[i,j,k,l,m,n] = 1}) = 0 and
+            card({(i,j,k,l,m,n) in B:
+                row >= k and row <= m and (col = l or col = n) and
+                x[i,j,k,l,m,n] = 1}) > 0} "|";
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+                row >= k and row <= m and (col = l or col = n) and
+                x[i,j,k,l,m,n] = 1}) = 0 and
+            card({(i,j,k,l,m,n) in B:
+                col >= l and col <= n and (row = k or row = m) and
+                x[i,j,k,l,m,n] = 1}) > 0} "-";
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+                row >= k and row <= m and (col = l or col = n) and
+                x[i,j,k,l,m,n] = 1}) = 0 and
+            card({(i,j,k,l,m,n) in B:
+                col >= l and col <= n and (row = k or row = m) and
+                x[i,j,k,l,m,n] = 1}) = 0} " ";
+
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+            col >= l and col < n and (row = k or row = m) and
+            x[i,j,k,l,m,n] = 1}) > 0} "---";
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+            col >= l and col < n and (row = k or row = m) and
+            x[i,j,k,l,m,n] = 1}) = 0} "   ";
+    }
+    printf "\n";
+
+    for { (col,p) in { cols, 1 }: card({ s in rows: s = row }) = 1 } {
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+            row >= k and row < m and (col = l or col = n) and
+            x[i,j,k,l,m,n] = 1}) > 0} "|";
+        printf{0..0: card({(i,j,k,l,m,n) in B:
+            row >= k and row < m and (col = l or col = n) and
+            x[i,j,k,l,m,n] = 1}) = 0} " ";
+        printf{0..0: card({ (i,j) in V: i = row and j = col}) > 0} " %2d", givens[row,col];
+        printf{0..0: card({ (i,j) in V: i = row and j = col}) = 0} "  .";
+    }
+    printf{0..0: card({ r in rows: r = row }) = 1} "|\n";
+}
+
+data;
+
+/* This Shikaku is from
+ * http://www.emn.fr/x-info/sdemasse/gccat/KShikaku.html#uid5449
+ */
+param givens : 1 2 3 4 5 6 7 8 9 10 :=
+           1   9 . . . 12 . . 5 . .
+           2   . . . . . . . . . .
+           3   . . . . . . . . . 6
+           4   8 . 6 . 8 . . . . .
+           5   . . . . . . . . . .
+           6   . . . . . . . . . .
+           7   . . . . . 6 . 8 . 12
+           8   4 . . . . . . . . .
+           9   . . . . . . . . . .
+          10   . . 3 . . 9 . . . 4
+           ;
+
+end;
Index: deps/glpk/examples/sorting.mod
===================================================================
--- deps/glpk/examples/sorting.mod	(revision 9)
+++ deps/glpk/examples/sorting.mod	(revision 9)
@@ -0,0 +1,67 @@
+/* sorting.mod - how to sort arrays in MathProg */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+#  Sometimes it is necessary to print parameters or variables in the
+#  order of ascending or descending their values. Suppose, for example,
+#  that we have the following subscripted parameter:
+
+set I := 1..12;
+
+param a{i in I} := Uniform(2, 7);
+
+#  If we print all its members:
+
+printf{i in I} "a[%d] = %g\n", i, a[i];
+
+#  the output may look like follows:
+#
+#  a[1]  = 2.64156
+#  a[2]  = 2.04798
+#  a[3]  = 2.14843
+#  a[4]  = 4.76896
+#  a[5]  = 6.09132
+#  a[6]  = 3.27780
+#  a[7]  = 4.06113
+#  a[8]  = 4.05898
+#  a[9]  = 6.63120
+#  a[10] = 6.50318
+#  a[11] = 3.46065
+#  a[12] = 4.69845
+#
+#  However, we would like the parameter members to appear in the order
+#  of ascending their values.
+#
+#  Introduce the following auxiliary parameter:
+
+param pos{i in I} :=
+      1 + card({j in I: a[j] < a[i] or a[j] = a[i] and j < i});
+
+#  where pos[i] = k means that in the sorted list member a[i] would
+#  have k-th position, 1 <= k <= |I|. Then introduce another auxiliary
+#  parameter:
+
+param ind{k in 1..card(I)} := sum{i in I: pos[i] = k} i;
+
+#  where ind[k] = i iff pos[k] = i.
+#
+#  Now, the following statement:
+
+printf{k in 1..card(I)} "a[%d] = %g\n", ind[k], a[ind[k]];
+
+#  prints the parameter members in the desired order:
+#
+#  a[2]  = 2.04798
+#  a[3]  = 2.14843
+#  a[1]  = 2.64156
+#  a[6]  = 3.27780
+#  a[11] = 3.46065
+#  a[8]  = 4.05898
+#  a[7]  = 4.06113
+#  a[12] = 4.69845
+#  a[4]  = 4.76896
+#  a[5]  = 6.09132
+#  a[10] = 6.50318
+#  a[9]  = 6.63120
+
+end;
Index: deps/glpk/examples/spp.mod
===================================================================
--- deps/glpk/examples/spp.mod	(revision 9)
+++ deps/glpk/examples/spp.mod	(revision 9)
@@ -0,0 +1,67 @@
+/* SPP, Shortest Path Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* Given a directed graph G = (V,E), its edge lengths c(i,j) for all
+   (i,j) in E, and two nodes s, t in V, the Shortest Path Problem (SPP)
+   is to find a directed path from s to t whose length is minimal. */
+
+param n, integer, > 0;
+/* number of nodes */
+
+set E, within {i in 1..n, j in 1..n};
+/* set of edges */
+
+param c{(i,j) in E};
+/* c[i,j] is length of edge (i,j); note that edge lengths are allowed
+   to be of any sign (positive, negative, or zero) */
+
+param s, in {1..n};
+/* source node */
+
+param t, in {1..n};
+/* target node */
+
+var x{(i,j) in E}, >= 0;
+/* x[i,j] = 1 means that edge (i,j) belong to shortest path;
+   x[i,j] = 0 means that edge (i,j) does not belong to shortest path;
+   note that variables x[i,j] are binary, however, there is no need to
+   declare them so due to the totally unimodular constraint matrix */
+
+s.t. r{i in 1..n}: sum{(j,i) in E} x[j,i] + (if i = s then 1) =
+                   sum{(i,j) in E} x[i,j] + (if i = t then 1);
+/* conservation conditions for unity flow from s to t; every feasible
+   solution is a path from s to t */
+
+minimize Z: sum{(i,j) in E} c[i,j] * x[i,j];
+/* objective function is the path length to be minimized */
+
+data;
+
+/* Optimal solution is 20 that corresponds to the following shortest
+   path: s = 1 -> 2 -> 4 -> 8 -> 6 = t */
+
+param n := 8;
+
+param s := 1;
+
+param t := 6;
+
+param : E :   c :=
+       1 2    1
+       1 4    8
+       1 7    6
+       2 4    2
+       3 2   14
+       3 4   10
+       3 5    6
+       3 6   19
+       4 5    8
+       4 8   13
+       5 8   12
+       6 5    7
+       7 4    5
+       8 6    4
+       8 7   10;
+
+end;
Index: deps/glpk/examples/spxsamp1.c
===================================================================
--- deps/glpk/examples/spxsamp1.c	(revision 9)
+++ deps/glpk/examples/spxsamp1.c	(revision 9)
@@ -0,0 +1,18 @@
+/* spxsamp1.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *P;
+      P = glp_create_prob();
+      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
+      glp_adv_basis(P, 0);
+      glp_simplex(P, NULL);
+      glp_print_sol(P, "25fv47.txt");
+      glp_delete_prob(P);
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/examples/spxsamp2.c
===================================================================
--- deps/glpk/examples/spxsamp2.c	(revision 9)
+++ deps/glpk/examples/spxsamp2.c	(revision 9)
@@ -0,0 +1,20 @@
+/* spxsamp2.c */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glpk.h>
+
+int main(void)
+{     glp_prob *P;
+      glp_smcp parm;
+      P = glp_create_prob();
+      glp_read_mps(P, GLP_MPS_DECK, NULL, "25fv47.mps");
+      glp_init_smcp(&parm);
+      parm.meth = GLP_DUAL;
+      glp_simplex(P, &parm);
+      glp_print_sol(P, "25fv47.txt");
+      glp_delete_prob(P);
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/examples/sql/README
===================================================================
--- deps/glpk/examples/sql/README	(revision 9)
+++ deps/glpk/examples/sql/README	(revision 9)
@@ -0,0 +1,5 @@
+This subdirectory contains files which demonstrate using data tables
+in MathProg models for MySQL and iODBC.
+
+Script mysql_setup.sh is used to load the data from the *.sql files to
+a MySQL database. Change the username, if necessary.
Index: deps/glpk/examples/sql/mysql_setup.sh
===================================================================
--- deps/glpk/examples/sql/mysql_setup.sh	(revision 9)
+++ deps/glpk/examples/sql/mysql_setup.sh	(revision 9)
@@ -0,0 +1,6 @@
+#!/bin/sh
+# This file can be used to create database glpk in MySQL.
+echo MySQL is called for user root. 
+mysql -f -u root -p < sudoku.sql
+echo MySQL is called for user root.
+mysql -f -u root -p < transp.sql
Index: deps/glpk/examples/sql/sudoku.sql
===================================================================
--- deps/glpk/examples/sql/sudoku.sql	(revision 9)
+++ deps/glpk/examples/sql/sudoku.sql	(revision 9)
@@ -0,0 +1,101 @@
+CREATE DATABASE glpk;
+CREATE USER glpk@localhost IDENTIFIED BY 'gnu';
+GRANT ALL PRIVILEGES ON glpk.* TO glpk@localhost;
+USE glpk;
+DROP TABLE sudoku;
+CREATE TABLE sudoku (
+  ID   INT ,
+  COL  INT ,
+  LIN  INT ,
+  VAL  INT ,
+  PRIMARY KEY ( ID, COL, LIN )
+  );
+DROP TABLE sudoku_solution;
+CREATE TABLE sudoku_solution (
+  ID   INT ,
+  COL  INT ,
+  LIN  INT ,
+  VAL  INT ,
+  PRIMARY KEY ( ID, COL, LIN )
+  );
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 1, 5);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 2, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 3, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 4, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 5, 4);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 6, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 7, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 8, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 1, 9, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 1, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 2, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 3, 3);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 4, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 5, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 6, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 7, 6);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 8, 2);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 2, 9, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 1, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 2, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 3, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 4, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 5, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 6, 9);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 7, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 8, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 3, 9, 4);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 1, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 2, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 3, 6);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 4, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 5, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 6, 7);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 7, 2);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 8, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 4, 9, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 1, 8);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 2, 1);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 3, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 4, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 5, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 6, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 7, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 8, 4);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 5, 9, 3);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 1, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 2, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 3, 9);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 4, 1);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 5, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 6, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 7, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 8, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 6, 9, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 1, 7);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 2, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 3, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 4, 5);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 5, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 6, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 7, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 8, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 7, 9, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 1, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 2, 9);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 3, 2);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 4, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 5, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 6, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 7, 8);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 8, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 8, 9, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 1, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 2, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 3, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 4, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 5, 3);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 6, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 7, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 8, 0);
+INSERT INTO sudoku (ID, COL, LIN, VAL) VALUES (1, 9, 9, 6);
Index: deps/glpk/examples/sql/sudoku_mysql.mod
===================================================================
--- deps/glpk/examples/sql/sudoku_mysql.mod	(revision 9)
+++ deps/glpk/examples/sql/sudoku_mysql.mod	(revision 9)
@@ -0,0 +1,113 @@
+/* SUDOKU, Number Placement Puzzle */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@mai2.rcnet.ru> */
+
+/* This example shows how to use the table statement.
+   The sudoku to be solves is read from file sudoku_in.csv.
+   The solution is written to sudoku_out.csv.
+   The file format is CSV as defined in
+     RFC 4180 - Common Format and MIME Type for
+     Comma-Separated Values (CSV) Files */
+
+/* Sudoku, also known as Number Place, is a logic-based placement
+   puzzle. The aim of the canonical puzzle is to enter a numerical
+   digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
+   subgrids (called "regions"), starting with various digits given in
+   some cells (the "givens"). Each row, column, and region must contain
+   only one instance of each numeral.
+
+   Example:
+
+   +-------+-------+-------+
+   | 5 3 . | . 7 . | . . . |
+   | 6 . . | 1 9 5 | . . . |
+   | . 9 8 | . . . | . 6 . |
+   +-------+-------+-------+
+   | 8 . . | . 6 . | . . 3 |
+   | 4 . . | 8 . 3 | . . 1 |
+   | 7 . . | . 2 . | . . 6 |
+   +-------+-------+-------+
+   | . 6 . | . . . | 2 8 . |
+   | . . . | 4 1 9 | . . 5 |
+   | . . . | . 8 . | . 7 9 |
+   +-------+-------+-------+
+
+   (From Wikipedia, the free encyclopedia.) */
+set fields dimen 2;
+
+param id;
+
+param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
+/* the "givens" */
+
+/*
+table ti IN 'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
+  'sudoku' :
+  fields <- [COL, LIN], givens ~ VAL;
+*/
+table ti IN 'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
+  'SELECT * FROM sudoku WHERE ID = ' & id :
+  fields <- [COL, LIN], givens ~ VAL;
+
+var x{i in 1..9, j in 1..9, k in 1..9}, binary;
+/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
+
+s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
+     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
+/* assign pre-defined numbers using the "givens" */
+
+s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
+/* each cell must be assigned exactly one number */
+
+s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
+/* cells in the same row must be assigned distinct numbers */
+
+s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
+/* cells in the same column must be assigned distinct numbers */
+
+s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
+     sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
+/* cells in the same region must be assigned distinct numbers */
+
+/* there is no need for an objective function here */
+
+solve;
+
+table ta{(i,j) in fields} OUT
+  'MySQL' 'Database=glpk;UID=glpk;PWD=gnu'
+  'DELETE FROM sudoku_solution'
+  'WHERE ID = ' & id & ';'
+  'INSERT INTO sudoku_solution'
+  '(ID, COL, LIN, VAL)'
+  'VALUES(?, ?, ?, ?);' :
+  id ~ ID, i ~ COL, j ~ LIN, (sum{k in 1..9} x[i,j,k] * k) ~ VAL;
+
+printf "\nSudoku to be solved\n";
+for {i in 1..9}
+{  for {0..0: i = 1 or i = 4 or i = 7}
+     printf " +-------+-------+-------+\n";
+   for {j in 1..9}
+   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
+      printf " %d", givens[i,j];
+      for {0..0: j = 9} printf(" |\n");
+   }
+   for {0..0: i = 9}
+   printf " +-------+-------+-------+\n";
+   }
+printf "\nSolution\n";
+for {i in 1..9}
+{  for {0..0: i = 1 or i = 4 or i = 7}
+      printf " +-------+-------+-------+\n";
+   for {j in 1..9}
+   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
+      printf " %d", sum{k in 1..9} x[i,j,k] * k;
+      for {0..0: j = 9} printf(" |\n");
+   }
+   for {0..0: i = 9}
+      printf " +-------+-------+-------+\n";
+}
+
+data;
+
+param id := 1;
+end;
Index: deps/glpk/examples/sql/sudoku_odbc.mod
===================================================================
--- deps/glpk/examples/sql/sudoku_odbc.mod	(revision 9)
+++ deps/glpk/examples/sql/sudoku_odbc.mod	(revision 9)
@@ -0,0 +1,111 @@
+/* SUDOKU, Number Placement Puzzle */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@mai2.rcnet.ru> */
+
+/* This example shows how to use the table statement.
+   The sudoku to be solves is read from file sudoku_in.csv.
+   The solution is written to sudoku_out.csv.
+   The file format is CSV as defined in
+     RFC 4180 - Common Format and MIME Type for
+     Comma-Separated Values (CSV) Files */
+
+/* Sudoku, also known as Number Place, is a logic-based placement
+   puzzle. The aim of the canonical puzzle is to enter a numerical
+   digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
+   subgrids (called "regions"), starting with various digits given in
+   some cells (the "givens"). Each row, column, and region must contain
+   only one instance of each numeral.
+
+   Example:
+
+   +-------+-------+-------+
+   | 5 3 . | . 7 . | . . . |
+   | 6 . . | 1 9 5 | . . . |
+   | . 9 8 | . . . | . 6 . |
+   +-------+-------+-------+
+   | 8 . . | . 6 . | . . 3 |
+   | 4 . . | 8 . 3 | . . 1 |
+   | 7 . . | . 2 . | . . 6 |
+   +-------+-------+-------+
+   | . 6 . | . . . | 2 8 . |
+   | . . . | 4 1 9 | . . 5 |
+   | . . . | . 8 . | . 7 9 |
+   +-------+-------+-------+
+
+   (From Wikipedia, the free encyclopedia.) */
+set fields dimen 2;
+
+param id;
+
+param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
+/* the "givens" */
+
+table ti IN 'iODBC'
+  'DSN=glpk;UID=glpk;PWD=gnu'
+  'SELECT * FROM sudoku'
+  'WHERE ID = ' & id :
+  fields <- [COL, LIN], givens ~ VAL;
+
+var x{i in 1..9, j in 1..9, k in 1..9}, binary;
+/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
+
+s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
+     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
+/* assign pre-defined numbers using the "givens" */
+
+s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
+/* each cell must be assigned exactly one number */
+
+s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
+/* cells in the same row must be assigned distinct numbers */
+
+s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
+/* cells in the same column must be assigned distinct numbers */
+
+s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
+     sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
+/* cells in the same region must be assigned distinct numbers */
+
+/* there is no need for an objective function here */
+
+
+solve;
+
+table ta {(i, j) in {i1 in 1..9} cross {i2 in 1..9}} OUT
+  'iODBC' 'DSN=glpk;UID=glpk;PWD=gnu'
+  'DELETE FROM sudoku_solution'
+  'WHERE ID = ' & id & ';'
+  'INSERT INTO sudoku_solution'
+  '(ID, COL, LIN, VAL)'
+  'VALUES(?, ?, ?, ?);' :
+  id ~ ID, i ~ COL, j ~ LIN, (sum{k in 1..9} x[i,j,k] * k) ~ VAL;
+
+printf "\nSudoku to be solved\n";
+for {i in 1..9}
+{  for {0..0: i = 1 or i = 4 or i = 7}
+     printf " +-------+-------+-------+\n";
+   for {j in 1..9}
+   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
+      printf " %d", givens[i,j];
+      for {0..0: j = 9} printf(" |\n");
+   }
+   for {0..0: i = 9}
+   printf " +-------+-------+-------+\n";
+   }
+printf "\nSolution\n";
+for {i in 1..9}
+{  for {0..0: i = 1 or i = 4 or i = 7}
+      printf " +-------+-------+-------+\n";
+   for {j in 1..9}
+   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
+      printf " %d", sum{k in 1..9} x[i,j,k] * k;
+      for {0..0: j = 9} printf(" |\n");
+   }
+   for {0..0: i = 9}
+      printf " +-------+-------+-------+\n";
+}
+
+data;
+
+param id := 1;
+end;
Index: deps/glpk/examples/sql/transp.sql
===================================================================
--- deps/glpk/examples/sql/transp.sql	(revision 9)
+++ deps/glpk/examples/sql/transp.sql	(revision 9)
@@ -0,0 +1,45 @@
+CREATE DATABASE glpk;
+CREATE USER glpk@localhost IDENTIFIED BY 'gnu';
+GRANT ALL PRIVILEGES ON glpk.* TO glpk@localhost;
+USE glpk;
+# production capacity
+DROP TABLE transp_capa;
+CREATE TABLE transp_capa (
+  PLANT TEXT(127),
+  CAPA  REAL,
+  PRIMARY KEY ( PLANT(127) )
+  );
+INSERT INTO transp_capa ( PLANT, CAPA ) VALUES ( 'Seattle',   350 );
+INSERT INTO transp_capa ( PLANT, CAPA ) VALUES ( 'San Diego', 600 );
+# demand
+DROP TABLE transp_demand;
+CREATE TABLE transp_demand (
+  MARKET TEXT(127),
+  DEMAND REAL,
+  PRIMARY KEY ( MARKET(127) )
+  );
+INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'New York', 325 );
+INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'Chicago', 300 );
+INSERT INTO transp_demand ( MARKET, DEMAND ) VALUES ( 'Topeka', 275 );
+# distance
+DROP TABLE transp_dist;
+CREATE TABLE transp_dist (
+  LOC1 TEXT(127),
+  LOC2 TEXT(127),
+  DIST REAL,
+  PRIMARY KEY ( LOC1(127), LOC2(127) )
+  );
+INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle',   'New York', 2.5 );
+INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle',   'Chicago', 1.7 );
+INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'Seattle',   'Topeka', 1.8 );
+INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'New York', 2.5 );
+INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'Chicago', 1.8 );
+INSERT INTO transp_dist ( LOC1, LOC2, DIST ) VALUES ( 'San Diego', 'Topeka', 1.4 );
+# result
+DROP TABLE transp_result;
+CREATE TABLE transp_result (
+  LOC1     TEXT(127),
+  LOC2     TEXT(127),
+  QUANTITY REAL,
+  PRIMARY KEY ( LOC1(127), LOC2(127) )
+  );
Index: deps/glpk/examples/sql/transp_mysql.mod
===================================================================
--- deps/glpk/examples/sql/transp_mysql.mod	(revision 9)
+++ deps/glpk/examples/sql/transp_mysql.mod	(revision 9)
@@ -0,0 +1,71 @@
+# A TRANSPORTATION PROBLEM
+#
+# This problem finds a least cost shipping schedule that meets
+# requirements at markets and supplies at factories.
+#
+#  References:
+#              Dantzig G B, "Linear Programming and Extensions."
+#              Princeton University Press, Princeton, New Jersey, 1963,
+#              Chapter 3-3.
+
+set I;
+/* canning plants */
+
+param a{i in I};
+/* capacity of plant i in cases */
+
+table plants IN "MySQL"
+  'Database=glpk;UID=glpk;PWD=gnu'
+  'SELECT PLANT, CAPA AS CAPACITY FROM transp_capa' :
+   I <- [ PLANT ], a ~ CAPACITY;
+
+set J;
+/* markets */
+
+param b{j in J};
+/* demand at market j in cases */
+
+table markets IN "MySQL"
+  'Database=glpk;UID=glpk;PWD=gnu'
+  'transp_demand' :
+  J <- [ MARKET ], b ~ DEMAND;
+
+param d{i in I, j in J};
+/* distance in thousands of miles */
+
+table dist IN "MySQL"
+  'Database=glpk;UID=glpk;PWD=gnu'
+  'transp_dist' :
+  [ LOC1, LOC2 ], d ~ DIST;
+
+param f;
+/* freight in dollars per case per thousand miles */
+
+param c{i in I, j in J} := f * d[i,j] / 1000;
+/* transport cost in thousands of dollars per case */
+
+var x{i in I, j in J} >= 0;
+/* shipment quantities in cases */
+
+minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
+/* total transportation costs in thousands of dollars */
+
+s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
+/* observe supply limit at plant i */
+
+s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
+/* satisfy demand at market j */
+
+solve;
+
+table result{i in I, j in J: x[i,j]} OUT "MySQL"
+  'Database=glpk;UID=glpk;PWD=gnu'
+  'DELETE FROM transp_result;'
+  'INSERT INTO transp_result VALUES (?,?,?)' :
+  i ~ LOC1, j ~ LOC2, x[i,j] ~ QUANTITY;
+
+data;
+
+param f := 90;
+
+end;
Index: deps/glpk/examples/sql/transp_odbc.mod
===================================================================
--- deps/glpk/examples/sql/transp_odbc.mod	(revision 9)
+++ deps/glpk/examples/sql/transp_odbc.mod	(revision 9)
@@ -0,0 +1,72 @@
+# A TRANSPORTATION PROBLEM
+#
+# This problem finds a least cost shipping schedule that meets
+# requirements at markets and supplies at factories.
+#
+#  References:
+#              Dantzig G B, "Linear Programming and Extensions."
+#              Princeton University Press, Princeton, New Jersey, 1963,
+#              Chapter 3-3.
+
+set I;
+/* canning plants */
+
+param a{i in I};
+/* capacity of plant i in cases */
+
+table plants IN "iODBC"
+  'DSN=glpk;UID=glpk;PWD=gnu'
+  'SELECT PLANT, CAPA AS CAPACITY'
+  'FROM transp_capa' :
+   I <- [ PLANT ], a ~ CAPACITY;
+
+set J;
+/* markets */
+
+param b{j in J};
+/* demand at market j in cases */
+
+table markets IN "iODBC"
+  'DSN=glpk;UID=glpk;PWD=gnu'
+  'transp_demand' :
+  J <- [ MARKET ], b ~ DEMAND;
+
+param d{i in I, j in J};
+/* distance in thousands of miles */
+
+table dist IN "iODBC"
+  'DSN=glpk;UID=glpk;PWD=gnu'
+  'transp_dist' :
+  [ LOC1, LOC2 ], d ~ DIST;
+
+param f;
+/* freight in dollars per case per thousand miles */
+
+param c{i in I, j in J} := f * d[i,j] / 1000;
+/* transport cost in thousands of dollars per case */
+
+var x{i in I, j in J} >= 0;
+/* shipment quantities in cases */
+
+minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
+/* total transportation costs in thousands of dollars */
+
+s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
+/* observe supply limit at plant i */
+
+s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
+/* satisfy demand at market j */
+
+solve;
+
+table result{i in I, j in J: x[i,j]} OUT "iODBC"
+  'DSN=glpk;UID=glpk;PWD=gnu'
+  'DELETE FROM transp_result;'
+  'INSERT INTO transp_result VALUES (?,?,?)' :
+  i ~ LOC1, j ~ LOC2, x[i,j] ~ QUANTITY;
+
+data;
+
+param f := 90;
+
+end;
Index: deps/glpk/examples/stigler.mod
===================================================================
--- deps/glpk/examples/stigler.mod	(revision 9)
+++ deps/glpk/examples/stigler.mod	(revision 9)
@@ -0,0 +1,411 @@
+/* STIGLER, original Stigler's 1939 diet problem */
+
+/* The Stigler Diet is an optimization problem named for George Stigler,
+   a 1982 Nobel Laureate in economics, who posed the following problem:
+   For a moderately active man weighing 154 pounds, how much of each of
+   77 foods should be eaten on a daily basis so that the man's intake of
+   nine nutrients will be at least equal to the recommended dietary
+   allowances (RDSs) suggested by the National Research Council in 1943,
+   with the cost of the diet being minimal?
+
+   The nutrient RDAs required to be met in Stigler's experiment were
+   calories, protein, calcium, iron, vitamin A, thiamine, riboflavin,
+   niacin, and ascorbic acid. The result was an annual budget allocated
+   to foods such as evaporated milk, cabbage, dried navy beans, and beef
+   liver at a cost of approximately $0.11 a day in 1939 U.S. dollars.
+
+   While the name "Stigler Diet" was applied after the experiment by
+   outsiders, according to Stigler, "No one recommends these diets for
+   anyone, let alone everyone." The Stigler diet has been much ridiculed
+   for its lack of variety and palatability, however his methodology has
+   received praise and is considered to be some of the earliest work in
+   linear programming.
+
+   The Stigler diet question is a linear programming problem. Lacking
+   any sophisticated method of solving such a problem, Stigler was
+   forced to utilize heuristic methods in order to find a solution. The
+   diet question originally asked in which quantities a 154 pound male
+   would have to consume 77 different foods in order to fulfill the
+   recommended intake of 9 different nutrients while keeping expense at
+   a minimum. Through "trial and error, mathematical insight and
+   agility," Stigler was able to eliminate 62 of the foods from the
+   original 77 (these foods were removed based because they lacked
+   nutrients in comparison to the remaining 15). From the reduced list,
+   Stigler calculated the required amounts of each of the remaining 15
+   foods to arrive at a cost-minimizing solution to his question.
+   According to Stigler's calculations, the annual cost of his solution
+   was $39.93 in 1939 dollars. When corrected for inflation using the
+   consumer price index, the cost of the diet in 2005 dollars is
+   $561.43. The specific combination of foods and quantities is as
+   follows:
+
+   Stigler's 1939 Diet
+
+   Food             Annual Quantities Annual Cost
+   ---------------- ----------------- -----------
+   Wheat Flour           370 lb.         $13.33
+   Evaporated Milk        57 cans          3.84
+   Cabbage               111 lb.           4.11
+   Spinach                23 lb.           1.85
+   Dried Navy Beans      285 lb.          16.80
+   ----------------------------------------------
+   Total Annual Cost                     $39.93
+
+   The 9 nutrients that Stigler's diet took into consideration and their
+   respective recommended daily amounts were:
+
+   Table of nutrients considered in Stigler's diet
+
+   Nutrient                  Daily Recommended Intake
+   ------------------------- ------------------------
+   Calories                       3,000 Calories
+   Protein                           70 grams
+   Calcium                           .8 grams
+   Iron                              12 milligrams
+   Vitamin A                      5,000 IU
+   Thiamine (Vitamin B1)            1.8 milligrams
+   Riboflavin (Vitamin B2)          2.7 milligrams
+   Niacin                            18 milligrams
+   Ascorbic Acid (Vitamin C)         75 milligrams
+
+   Seven years after Stigler made his initial estimates, the development
+   of George Dantzig's Simplex algorithm made it possible to solve the
+   problem without relying on heuristic methods. The exact value was
+   determined to be $39.69 (using the original 1939 data). Dantzig's
+   algorithm describes a method of traversing the vertices of a polytope
+   of N+1 dimensions in order to find the optimal solution to a specific
+   situation.
+
+   (From Wikipedia, the free encyclopedia.) */
+
+/* Translated from GAMS by Andrew Makhorin <mao@gnu.org>.
+
+   For the original GAMS model stigler1939.gms see [3].
+
+   References:
+
+   1. George J. Stigler, "The Cost of Subsistence," J. Farm Econ. 27,
+      1945, pp. 303-14.
+
+   2. National Research Council, "Recommended Daily Allowances," Reprint
+      and Circular Series No. 115, January, 1943.
+
+   3. Erwin Kalvelagen, "Model building with GAMS," Chapter 2, "Building
+      linear programming models," pp. 128-34. */
+
+set C;
+/* commodities */
+
+check card(C) = 77;
+/* there must be 77 commodities */
+
+set N;
+/* nutrients */
+
+param data{c in C, {"price", "weight"} union N};
+/* nutritive values per dollar of expenditure */
+
+param allowance{n in N};
+/* recommended daily allowance for a moderately active man */
+
+var x{c in C}, >= 0;
+/* dollars of food to be purchased daily */
+
+s.t. nb{n in N}: sum{c in C} data[c,n] * x[c] >= allowance[n];
+/* nutrient balance */
+
+minimize cost: sum{c in C} x[c];
+/* total food bill */
+
+solve;
+
+param days := 365.25;
+/* days in a year */
+
+param commodity{c in C}, symbolic;
+
+param unit{c in C}, symbolic;
+
+printf "\n";
+printf "MINIMUM COST ANNUAL DIET\n";
+printf "\n";
+printf "        Commodity            Unit     Quantity     Cost   \n";
+printf "------------------------- ---------- ---------- ----------\n";
+printf{c in C: x[c] != 0} "%-25s %10s %10.2f   $%7.2f\n", commodity[c],
+   unit[c], 100 * days * x[c] / data[c,"price"], days * x[c];
+printf "                                         -----------------\n";
+printf "                                         Total:   $%7.2f\n",
+   days * sum{c in C} x[c];
+printf "\n";
+
+data;
+
+param : C :    commodity                   unit :=
+flour          "Wheat Flour (Enriched)"    "10 lb."
+macaroni       "Macaroni"                  "1 lb."
+cereal         "Wheat Cereal (Enriched)"   "28 oz."
+cornflakes     "Corn Flakes"               "8 oz."
+cornmeal       "Corn Meal"                 "1 lb."
+grits          "Hominy Grits"              "24 oz."
+rice           "Rice"                      "1 lb."
+oats           "Rolled Oats"               "1 lb."
+whitebread     "White Bread (Enriched)"    "1 lb."
+wheatbread     "Whole Wheat Bread"         "1 lb."
+ryebread       "Rye Bread"                 "1 lb."
+poundcake      "Pound Cake"                "1 lb."
+crackers       "Soda Crackers"             "1 lb."
+milk           "Milk"                      "1 qt."
+evapmild       "Evaporated Milk (can)"     "14.5 oz."
+butter         "Butter"                    "1 lb."
+margarine      "Oleomargarine"             "1 lb."
+eggs           "Eggs"                      "1 doz."
+cheese         "Cheese (Cheddar)"          "1 lb."
+cream          "Cream"                     "1/2 pt."
+peanutbutter   "Peanut Butter"             "1 lb."
+mayonnaise     "Mayonnaise"                "1/2 pt."
+crisco         "Crisco"                    "1 lb."
+lard           "Lard"                      "1 lb."
+sirloinsteak   "Sirloin Steak"             "1 lb."
+roundsteak     "Round Steak"               "1 lb."
+ribroast       "Rib Roast"                 "1 lb."
+chuckroast     "Chuck Roast"               "1 lb."
+plate          "Plate"                     "1 lb."
+liver          "Liver (Beef)"              "1 lb."
+lambleg        "Leg of Lamb"               "1 lb."
+lambchops      "Lamb Chops (Rib)"          "1 lb."
+porkchops      "Pork Chops"                "1 lb."
+porkroast      "Pork Loin Roast"           "1 lb."
+bacon          "Bacon"                     "1 lb."
+ham            "Ham - smoked"              "1 lb."
+saltpork       "Salt Pork"                 "1 lb."
+chicken        "Roasting Chicken"          "1 lb."
+veal           "Veal Cutlets"              "1 lb."
+salmon         "Salmon, Pink (can)"        "16 oz."
+apples         "Apples"                    "1 lb."
+bananas        "Bananas"                   "1 lb."
+lemons         "Lemons"                    "1 doz."
+oranges        "Oranges"                   "1 doz."
+greenbeans     "Green Beans"               "1 lb."
+cabbage        "Cabbage"                   "1 lb."
+carrots        "Carrots"                   "1 bunch"
+celery         "Celery"                    "1 stalk"
+lettuce        "Lettuce"                   "1 head"
+onions         "Onions"                    "1 lb."
+potatoes       "Potatoes"                  "15 lb."
+spinach        "Spinach"                   "1 lb."
+sweetpotato    "Sweet Potatoes"            "1 lb."
+peaches        "Peaches (can)"             "No. 2 1/2"
+pears          "Pears (can)"               "No. 2 1/2"
+pineapple      "Pineapple (can)"           "No. 2 1/2"
+asparagus      "Asparagus (can)"           "No. 2"
+cannedgrbn     "Grean Beans (can)"         "No. 2"
+porkbeans      "Pork and Beans (can)"      "16 oz."
+corn           "Corn (can)"                "No. 2"
+peas           "Peas (can)"                "No. 2"
+tomatoes       "Tomatoes (can)"            "No. 2"
+tomatosoup     "Tomato Soup (can)"         "10 1/2 oz."
+driedpeach     "Peaches, Dried"            "1 lb."
+prunes         "Prunes, Dried"             "1 lb."
+raisins        "Raisins, Dried"            "15 oz."
+driedpeas      "Peas, Dried"               "1 lb."
+limabeans      "Lima Beans, Dried"         "1 lb."
+navybeans      "Navy Beans, Dried"         "1 lb."
+coffee         "Coffee"                    "1 lb."
+tea            "Tea"                       "1/4 lb."
+cocoa          "Cocoa"                     "8 oz."
+chocolate      "Chocolate"                 "8 oz."
+sugar          "Sugar"                     "10 lb."
+cornsirup      "Corn Sirup"                "24 oz."
+molasses       "Molasses"                  "18 oz."
+stawberry      "Strawberry Preserve"       "1 lb."
+;
+
+set N :=
+calories       /* Calories, unit = 1000 */
+protein        /* Protein, unit = grams */
+calcium        /* Calcium, unit = grams */
+iron           /* Iron, unit = milligrams */
+vitaminA       /* Vitamin A, unit = 1000 International Units */
+thiamine       /* Thiamine, Vit. B1, unit = milligrams */
+riboflavin     /* Riboflavin, Vit. B2, unit = milligrams */
+niacin         /* Niacin (Nicotinic Acid), unit = milligrams */
+ascorbicAcid   /* Ascorbic Acid, Vit. C, unit = milligrams */
+;
+
+param data
+:             price   weight calories protein  calcium   iron :=
+#            aug. 15  edible
+#             1939    per $1
+#           (cents)   (grams) (1000)  (grams)  (grams)   (mg.)
+flour         36.0    12600    44.7     1411     2.0      365
+macaroni      14.1     3217    11.6      418      .7       54
+cereal        24.2     3280    11.8      377    14.4      175
+cornflakes     7.1     3194    11.4      252      .1       56
+cornmeal       4.6     9861    36.0      897     1.7       99
+grits          8.5     8005    28.6      680      .8       80
+rice           7.5     6048    21.2      460      .6       41
+oats           7.1     6389    25.3      907     5.1      341
+whitebread     7.9     5742    15.6      488     2.5      115
+wheatbread     9.1     4985    12.2      484     2.7      125
+ryebread       9.2     4930    12.4      439     1.1       82
+poundcake     24.8     1829     8.0      130      .4       31
+crackers      15.1     3004    12.5      288      .5       50
+milk          11.0     8867     6.1      310    10.5       18
+evapmild       6.7     6035     8.4      422    15.1        9
+butter        20.8     1473    10.8        9      .2        3
+margarine     16.1     2817    20.6       17      .6        6
+eggs          32.6     1857     2.9      238     1.0       52
+cheese        24.2     1874     7.4      448    16.4       19
+cream         14.1     1689     3.5       49     1.7        3
+peanutbutter  17.9     2534    15.7      661     1.0       48
+mayonnaise    16.7     1198     8.6       18      .2        8
+crisco        20.3     2234    20.1        0      .0        0
+lard           9.8     4628    41.7        0      .0        0
+sirloinsteak  39.6     1145     2.9      166      .1       34
+roundsteak    36.4     1246     2.2      214      .1       32
+ribroast      29.2     1553     3.4      213      .1       33
+chuckroast    22.6     2007     3.6      309      .2       46
+plate         14.6     3107     8.5      404      .2       62
+liver         26.8     1692     2.2      333      .2      139
+lambleg       27.6     1643     3.1      245      .1       20
+lambchops     36.6     1239     3.3      140      .1       15
+porkchops     30.7     1477     3.5      196      .2       80
+porkroast     24.2     1874     4.4      249      .3       37
+bacon         25.6     1772    10.4      152      .2       23
+ham           27.4     1655     6.7      212      .2       31
+saltpork      16.0     2835    18.8      164      .1       26
+chicken       30.3     1497     1.8      184      .1       30
+veal          42.3     1072     1.7      156      .1       24
+salmon        13.0     3489     5.8      705     6.8       45
+apples         4.4     9072     5.8       27      .5       36
+bananas        6.1     4982     4.9       60      .4       30
+lemons        26.0     2380     1.0       21      .5       14
+oranges       30.9     4439     2.2       40     1.1       18
+greenbeans     7.1     5750     2.4      138     3.7       80
+cabbage        3.7     8949     2.6      125     4.0       36
+carrots        4.7     6080     2.7       73     2.8       43
+celery         7.3     3915      .9       51     3.0       23
+lettuce        8.2     2247      .4       27     1.1       22
+onions         3.6    11844     5.8      166     3.8       59
+potatoes      34.0    16810    14.3      336     1.8      118
+spinach        8.1     4592     1.1      106      .0      138
+sweetpotato    5.1     7649     9.6      138     2.7       54
+peaches       16.8     4894     3.7       20      .4       10
+pears         20.4     4030     3.0        8      .3        8
+pineapple     21.3     3993     2.4       16      .4        8
+asparagus     27.7     1945      .4       33      .3       12
+cannedgrbn    10.0     5386     1.0       54     2.0       65
+porkbeans      7.1     6389     7.5      364     4.0      134
+corn          10.4     5452     5.2      136      .2       16
+peas          13.8     4109     2.3      136      .6       45
+tomatoes       8.6     6263     1.3       63      .7       38
+tomatosoup     7.6     3917     1.6       71      .6       43
+driedpeach    15.7     2889     8.5       87     1.7      173
+prunes         9.0     4284    12.8       99     2.5      154
+raisins        9.4     4524    13.5      104     2.5      136
+driedpeas      7.9     5742    20.0     1367     4.2      345
+limabeans      8.9     5097    17.4     1055     3.7      459
+navybeans      5.9     7688    26.9     1691    11.4      792
+coffee        22.4     2025      .0        0      .0        0
+tea           17.4      652      .0        0      .0        0
+cocoa          8.6     2637     8.7      237     3.0       72
+chocolate     16.2     1400     8.0       77     1.3       39
+sugar         51.7     8773    34.9        0      .0        0
+cornsirup     13.7     4996    14.7        0      .5       74
+molasses      13.6     3752     9.0        0    10.3      244
+stawberry     20.5     2213     6.4       11      .4        7
+
+:           vitaminA thiamine riboflavin  niacin  ascorbicAcid :=
+#          (1000 IU)  (mg.)      (mg.)     (mg.)     (mg.)
+flour           .0    55.4       33.3       441         0
+macaroni        .0     3.2        1.9        68         0
+cereal          .0    14.4        8.8       114         0
+cornflakes      .0    13.5        2.3        68         0
+cornmeal      30.9    17.4        7.9       106         0
+grits           .0    10.6        1.6       110         0
+rice            .0     2.0        4.8        60         0
+oats            .0    37.1        8.9        64         0
+whitebread      .0    13.8        8.5       126         0
+wheatbread      .0    13.9        6.4       160         0
+ryebread        .0     9.9        3.0        66         0
+poundcake     18.9     2.8        3.0        17         0
+crackers        .0      .0         .0         0         0
+milk          16.8     4.0       16.0         7       177
+evapmild      26.0     3.0       23.5        11        60
+butter        44.2      .0         .2         2         0
+margarine     55.8      .2         .0         0         0
+eggs          18.6     2.8        6.5         1         0
+cheese        28.1      .8       10.3         4         0
+cream         16.9      .6        2.5         0        17
+peanutbutter    .0     9.6        8.1       471         0
+mayonnaise     2.7      .4         .5         0         0
+crisco          .0      .0         .0         0         0
+lard            .2      .0         .5         5         0
+sirloinsteak    .2     2.1        2.9        69         0
+roundsteak      .4     2.5        2.4        87         0
+ribroast        .0      .0        2.0         0         0
+chuckroast      .4     1.0        4.0       120         0
+plate           .0      .9         .0         0         0
+liver        169.2     6.4       50.8       316       525
+lambleg         .0     2.8        3.0        86         0
+lambchops       .0     1.7        2.7        54         0
+porkchops       .0    17.4        2.7        60         0
+porkroast       .0    18.2        3.6        79         0
+bacon           .0     1.8        1.8        71         0
+ham             .0     9.9        3.3        50         0
+saltpork        .0     1.4        1.8         0         0
+chicken         .1      .9        1.8        68        46
+veal            .0     1.4        2.4        57         0
+salmon         3.5     1.0        4.9       209         0
+apples         7.3     3.6        2.7         5       544
+bananas       17.4     2.5        3.5        28       498
+lemons          .0      .5         .0         4       952
+oranges       11.1     3.6        1.3        10      1993
+greenbeans    69.0     4.3        5.8        37       862
+cabbage        7.2     9.0        4.5        26      5369
+carrots      188.5     6.1        4.3        89       608
+celery          .9     1.4        1.4         9       313
+lettuce      112.4     1.8        3.4        11       449
+onions        16.6     4.7        5.9        21      1184
+potatoes       6.7    29.4        7.1       198      2522
+spinach      918.4     5.7       13.8        33      2755
+sweetpotato  290.7     8.4        5.4        83      1912
+peaches       21.5      .5        1.0        31       196
+pears           .8      .8         .8         5        81
+pineapple      2.0     2.8         .8         7       399
+asparagus     16.3     1.4        2.1        17       272
+cannedgrbn    53.9     1.6        4.3        32       431
+porkbeans      3.5     8.3        7.7        56         0
+corn          12.0     1.6        2.7        42       218
+peas          34.9     4.9        2.5        37       370
+tomatoes      53.2     3.4        2.5        36      1253
+tomatosoup    57.9     3.5        2.4        67       862
+driedpeach    86.8     1.2        4.3        55        57
+prunes        85.7     3.9        4.3        65       257
+raisins        4.5     6.3        1.4        24       136
+driedpeas      2.9    28.7       18.4       162         0
+limabeans      5.1    26.9       38.2        93         0
+navybeans       .0    38.4       24.6       217         0
+coffee          .0     4.0        5.1        50         0
+tea             .0      .0        2.3        42         0
+cocoa           .0     2.0       11.9        40         0
+chocolate       .0      .9        3.4        14         0
+sugar           .0      .0         .0         0         0
+cornsirup       .0      .0         .0         5         0
+molasses        .0     1.9        7.5       146         0
+stawberry       .2      .2         .4         3         0
+;
+
+param allowance :=
+calories       3
+protein       70
+calcium         .8
+iron          12
+vitaminA       5
+thiamine       1.8
+riboflavin     2.7
+niacin        18
+ascorbicAcid  75
+;
+
+end;
Index: deps/glpk/examples/sudoku.dat
===================================================================
--- deps/glpk/examples/sudoku.dat	(revision 9)
+++ deps/glpk/examples/sudoku.dat	(revision 9)
@@ -0,0 +1,16 @@
+/* sudoku.dat, a hard Sudoku puzzle which causes branching */
+
+data;
+
+param givens : 1 2 3 4 5 6 7 8 9 :=
+           1   1 . . . . . 7 . .
+           2   . 2 . . . . 5 . .
+           3   6 . . 3 8 . . . .
+           4   . 7 8 . . . . . .
+           5   . . . 6 . 9 . . .
+           6   . . . . . . 1 4 .
+           7   . . . . 2 5 . . 9
+           8   . . 3 . . . . 6 .
+           9   . . 4 . . . . . 2 ;
+
+end;
Index: deps/glpk/examples/sudoku.mod
===================================================================
--- deps/glpk/examples/sudoku.mod	(revision 9)
+++ deps/glpk/examples/sudoku.mod	(revision 9)
@@ -0,0 +1,84 @@
+/* SUDOKU, Number Placement Puzzle */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* Sudoku, also known as Number Place, is a logic-based placement
+   puzzle. The aim of the canonical puzzle is to enter a numerical
+   digit from 1 through 9 in each cell of a 9x9 grid made up of 3x3
+   subgrids (called "regions"), starting with various digits given in
+   some cells (the "givens"). Each row, column, and region must contain
+   only one instance of each numeral.
+
+   Example:
+
+   +-------+-------+-------+
+   | 5 3 . | . 7 . | . . . |
+   | 6 . . | 1 9 5 | . . . |
+   | . 9 8 | . . . | . 6 . |
+   +-------+-------+-------+
+   | 8 . . | . 6 . | . . 3 |
+   | 4 . . | 8 . 3 | . . 1 |
+   | 7 . . | . 2 . | . . 6 |
+   +-------+-------+-------+
+   | . 6 . | . . . | 2 8 . |
+   | . . . | 4 1 9 | . . 5 |
+   | . . . | . 8 . | . 7 9 |
+   +-------+-------+-------+
+
+   (From Wikipedia, the free encyclopedia.) */
+
+param givens{1..9, 1..9}, integer, >= 0, <= 9, default 0;
+/* the "givens" */
+
+var x{i in 1..9, j in 1..9, k in 1..9}, binary;
+/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
+
+s.t. fa{i in 1..9, j in 1..9, k in 1..9: givens[i,j] != 0}:
+     x[i,j,k] = (if givens[i,j] = k then 1 else 0);
+/* assign pre-defined numbers using the "givens" */
+
+s.t. fb{i in 1..9, j in 1..9}: sum{k in 1..9} x[i,j,k] = 1;
+/* each cell must be assigned exactly one number */
+
+s.t. fc{i in 1..9, k in 1..9}: sum{j in 1..9} x[i,j,k] = 1;
+/* cells in the same row must be assigned distinct numbers */
+
+s.t. fd{j in 1..9, k in 1..9}: sum{i in 1..9} x[i,j,k] = 1;
+/* cells in the same column must be assigned distinct numbers */
+
+s.t. fe{I in 1..9 by 3, J in 1..9 by 3, k in 1..9}:
+     sum{i in I..I+2, j in J..J+2} x[i,j,k] = 1;
+/* cells in the same region must be assigned distinct numbers */
+
+/* there is no need for an objective function here */
+
+solve;
+
+for {i in 1..9}
+{  for {0..0: i = 1 or i = 4 or i = 7}
+      printf " +-------+-------+-------+\n";
+   for {j in 1..9}
+   {  for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
+      printf " %d", sum{k in 1..9} x[i,j,k] * k;
+      for {0..0: j = 9} printf(" |\n");
+   }
+   for {0..0: i = 9}
+      printf " +-------+-------+-------+\n";
+}
+
+data;
+
+/* These data correspond to the example above. */
+
+param givens : 1 2 3 4 5 6 7 8 9 :=
+           1   5 3 . . 7 . . . .
+           2   6 . . 1 9 5 . . .
+           3   . 9 8 . . . . 6 .
+           4   8 . . . 6 . . . 3
+           5   4 . . 8 . 3 . . 1
+           6   7 . . . 2 . . . 6
+           7   . 6 . . . . 2 8 .
+           8   . . . 4 1 9 . . 5
+           9   . . . . 8 . . 7 9 ;
+
+end;
Index: deps/glpk/examples/t1.cs
===================================================================
--- deps/glpk/examples/t1.cs	(revision 9)
+++ deps/glpk/examples/t1.cs	(revision 9)
@@ -0,0 +1,99 @@
+/*Find the minimum value which satisfies the linear inequality:
+    a*x + b*y >= 1 {a,b,x,y Integers} {a,b > 0} {a,b entered on command line}
+
+  Nigel_Galloway@operamail.com
+  February 2008
+*/
+using System;
+using System.Runtime.InteropServices;
+
+unsafe class GLPK{
+  double *lp;
+  public int a;
+  public int b;
+
+  const string glpkLibrary = "libglpk.so";
+  readonly int GLP_FR = 1;
+  readonly int GLP_IV = 2;
+  readonly int GLP_DB = 4;
+  struct ConstraintMatrix{
+    public fixed int ia[3];
+    public fixed int ja[3];
+    public fixed double ar[3];
+  }
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern double* glp_create_prob();
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_add_rows(double* lp, int rows);
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_add_cols(double* lp, int cols);
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_set_col_bnds(double* lp, int col, int bound_type, double lower_bound, double upper_bound);
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_set_col_kind(double* lp, int col, int kind);
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_load_matrix(double* lp, int elements, int* ia, int* ja, double* ar);
+  public GLPK(int a, int b){
+    this.a = a;
+    this.b = b;
+    lp = glp_create_prob();
+    //Col 1 is x, Col 2 is y
+    glp_add_rows(lp, 1);
+    glp_add_cols(lp, 2);
+    glp_set_col_bnds(lp, 1, GLP_FR, 0.0, 0.0);
+    glp_set_col_bnds(lp, 2, GLP_FR, 0.0, 0.0);
+    glp_set_col_kind(lp, 1, GLP_IV);
+    glp_set_col_kind(lp, 2, GLP_IV);
+    //Row 1 is a*x + b*y
+    ConstraintMatrix CM = new ConstraintMatrix();
+    CM.ia[1]=1; CM.ja[1]=1; CM.ar[1]=a;
+    CM.ia[2]=1; CM.ja[2]=2; CM.ar[2]=b;
+    glp_load_matrix(lp, 2, CM.ia, CM.ja, CM.ar);
+    Console.WriteLine("Hello Nigel");
+  }
+
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_set_row_bnds(double* lp, int row, int bound_type, double lower_bound, double upper_bound);
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_simplex(double* lp, void* options);
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_intopt(double* lp, void* options);
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern double glp_mip_col_val(double* lp, int col);
+  public int betterGuess(int upper_bound){
+    //Find a new guess less than the old guess: 1 <= (a*x + b*y) <= (old guess - 1)
+    glp_set_row_bnds(lp, 1, GLP_DB, 1.0, ((double)upper_bound)-0.5);
+    glp_simplex(lp, null);
+    glp_intopt(lp, null);
+    int x = (int)glp_mip_col_val(lp, 1);
+    int y = (int)glp_mip_col_val(lp, 2);
+    int nextGuess = a*x + b*y;
+    Console.WriteLine("x = {0}, y = {1}, a*x + b*y = {2}",x,y,nextGuess);
+    return nextGuess;
+  }
+
+  [DllImport(glpkLibrary, SetLastError=true)]
+  static extern void glp_delete_prob(double* lp);
+  ~GLPK(){
+    glp_delete_prob(lp);
+    Console.WriteLine("Goodbye Nigel");
+  }
+
+}
+
+class test{
+  static bool isMinimum(int a, int b, int guess){
+    Console.WriteLine("Trying {0}",guess);
+    if (a%guess > 0) return false;
+    if (b%guess > 0) return false;
+    Console.WriteLine("Solution is {0}",guess);
+    return true;
+  }
+
+  public static void Main(string[] args){
+    Console.WriteLine("a = {0}, b = {1}",args[0], args[1]);
+    GLPK lp = new GLPK(Int32.Parse(args[0]),Int32.Parse(args[1]));
+    int guess = (lp.a > lp.b) ? lp.b : lp.a;
+    while (!isMinimum(lp.a,lp.b,guess)) guess = lp.betterGuess(guess);
+  }
+}
Index: deps/glpk/examples/tas.mod
===================================================================
--- deps/glpk/examples/tas.mod	(revision 9)
+++ deps/glpk/examples/tas.mod	(revision 9)
@@ -0,0 +1,486 @@
+/* TAS, Tail Assignment Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Tail Assignment Problem (TAS) is to construct rosters for a set
+   of aircrafts (tails), which cover all flights for a given scheduling
+   period.
+
+   This model includes only flight connection constraints while other
+   constraints (for example, maintenance constraints) are ignored. Such
+   simplification allows using a single commodity network to model the
+   problem, where commodity corresponds to the set of aircrafts.
+
+   Nodes of the network are activities. They include all flights plus
+   two dummy nodes (activities): source node, s, corresponding to
+   initial activity of each aircraft, and sink node t, corresponding to
+   final activity of each aircraft. Arc v->v' exists in the network if
+   and only if the same aircraft is able to operate activity v and then
+   immediately activity v'. In partucular, arcs s->f and f->t exist for
+   all flights f. Arcs f->f', where f and f' are some flights, exist
+   only if the connection time (which is the difference between the
+   departure time of f' and the arrival time of f) is not less than a
+   given minimal connection time.
+
+   Reference:
+   M. Groenkvist, "The Tail Assignment Problem," Dept. of Comp. Sci.
+   and Eng., Chalmers University of Technology and Goeteborg University,
+   Goeteborg, Sweden, August 2005. */
+
+########################################################################
+
+param nf, integer, > 0;
+/* number of flights */
+
+set F := 1..nf;
+/* set of flights (for a given period from timetable) */
+
+param hub{f in F}, in {1, 2};
+/* hub[f] = 1: Sheremetyevo-1
+   hub[f] = 2: Sheremetyevo-2 */
+
+param dest{f in F}, symbolic;
+/* destination airport (IATA code) */
+
+param fno1{f in F}, integer;
+/* first leg flight number */
+
+param dep1{f in F}, integer, >= 0;
+/* departure time from Sheremetyevo airport, in minutes */
+
+check{f in F: f < nf}: dep1[f] <= dep1[f+1];
+/* all flights must be ordered by ascending of the departure time */
+
+param arr1{f in F}, integer, >= 0;
+/* arrival time to destination airport, in minutes */
+
+param fno2{f in F}, integer;
+/* second leg flight number */
+
+param dep2{f in F}, integer, >= 0;
+/* departure time from destination airport, in minutes */
+
+param arr2{f in F}, integer, >= 0;
+/* arrival time to Sheremetyevo airport, in minutes */
+
+param mct1, integer, >= 0, default 80;
+/* minimal connection time (within SVO1 or SVO2), in minutes */
+
+param mct2, integer, >= 0, default 150;
+/* minimal connection time (between SVO1 and SVO2), in minutes */
+
+set E := setof{f in F, ff in F: arr2[f] + (if hub[f] = hub[ff] then
+   mct1 else mct2) <= dep1[ff]} (f, ff);
+/* connection network; arc f->ff is in E, iff the same aircraft can be
+   assigned to flight f and then immediately to flight ff */
+
+var s{f in F}, >= 0;
+/* s[f] is a flow from source node to node f */
+
+var x{(f,ff) in E}, >= 0;
+/* x[f,ff] is a flow from node f to node ff */
+
+var t{f in F}, >= 0;
+/* t[f] is a flow from node f to sink node */
+
+s.t. into{f in F}: s[f] + sum{(ff,f) in E} x[ff,f] = 1;
+/* exactly one aircraft must come into each node f */
+
+s.t. from{f in F}: t[f] + sum{(f,ff) in E} x[f,ff] = 1;
+/* exactly one aircraft must come from each node f */
+
+minimize obj: sum{f in F} s[f];
+/* minimize the number aircrafts sufficient to cover all flights */
+
+solve;
+
+########################################################################
+
+param na := floor(sum{f in F} s[f] + .5);
+/* minimal number of aircrafts found */
+
+printf "At least %d aircrafts needed\n", na;
+
+set A := 1..na;
+/* set of aircrafts */
+
+printf "Building rosters...\n";
+
+param tail{f in F}, in A, :=
+/* tail[f] is the number of an aircraft assigned to flight f */
+
+   if f = 1 then 1
+   /* assign aircraft 1 to the earliest flight */
+
+   else if s[f] >= 0.9 then (max{ff in 1..f-1} tail[ff]) + 1
+   /* if f is the first flight in a roster, assign to it a next
+      aircraft */
+
+   else sum{(ff,f) in E} tail[ff] * (if x[ff,f] >= 0.9 then 1);
+   /* otherwise, assign to flight f the same aircraft, which is
+      assigned to a preceding flight in the roster */
+
+########################################################################
+
+param file, symbolic, default "tas.ps";
+/* file to output the assignment chart in postscript format */
+
+param title, symbolic, default "(no title)";
+/* chart title */
+
+param left, default 25;
+/* left margin, in mm */
+
+param top, default 25;
+/* top margin, in mm */
+
+param right, default 20;
+/* right margin, in mm */
+
+param bottom, default 15;
+/* bottom margin, in mm */
+
+param sx := 297 - left - right;
+/* chart area horizontal size, in mm */
+
+param sy := 210 - top - bottom;
+/* chart area vertical size, in mm */
+
+param gap, default sy / (na - 1);
+/* gap between rosters, in mm */
+
+printf "Writing assignment chart to %s...\n", file;
+
+printf "%%!PS-Adobe-3.0\n" > file;
+printf "%%%%Title: Tail Assignment Chart\n" >> file;
+printf "%%%%Creator: GLPK MathProg\n" >> file;
+printf "%%%%BoundingBox: 0 0 595 842\n" >> file;
+printf "%%%%EndComments\n" >> file;
+printf "<</PageSize [595 842]>> setpagedevice\n" >> file;
+printf "72 25.4 div dup scale\n" >> file;
+printf "210 %.3f sub %.3f translate\n", bottom, left >> file;
+printf "90 rotate\n" >> file;
+
+printf "/HelveticaBold findfont 5 scalefont setfont\n" >> file;
+printf "%.3f %.3f moveto (%s) dup show\n", 0, sy + 5, title >> file;
+
+param period := floor((max{f in F} arr2[f]) / 60. + .5);
+/* period duration, in hours */
+
+/* vertical bars */
+printf ".8 .8 .8 setrgbcolor\n" >> file;
+for {tt in 0..period}
+{  printf "%s setlinewidth\n",
+      if tt mod 24 = 0 then ".5" else "0" >> file;
+   printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
+      tt * (sx / period), 0, tt * (sx / period),
+      sy + (if tt mod 24 = 0 then 2) >> file;
+}
+
+/* rosters */
+for {a in A}
+{  printf "0 0 0 setrgbcolor\n" >> file;
+   printf "0 setlinewidth\n" >> file;
+   printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
+      0, sy - gap * (a - 1), sx, sy - gap * (a - 1) >> file;
+   printf "/Dingbats findfont 4 scalefont setfont\n" >> file;
+   printf "%.3f %.3f moveto <28> dup show\n",
+      -4, sy - gap * (a - 1) - 1.4, a >> file;
+   printf "/Helvetica findfont 3 scalefont setfont\n" >> file;
+   printf "%.3f %.3f moveto (%2d) dup show\n",
+      -9, sy - gap * (a - 1) - 1.2, a >> file;
+   for {f in F: tail[f] == a}
+   {  printf "0 0 %s setrgbcolor\n",
+         if hub[f] = 1 then "0" else ".8" >> file;
+      printf "1 setlinewidth\n" >> file;
+      printf "newpath %.3f %.3f moveto %.3f %.3f lineto stroke\n",
+         dep1[f] / 60 * (sx / period), sy - gap * (a - 1),
+         arr2[f] / 60 * (sx / period), sy - gap * (a - 1) >> file;
+      printf "/Helvetica findfont 1.8 scalefont setfont\n" >> file;
+      printf "%.3f %.3f moveto (%02d:%02d %s) dup show\n",
+         dep1[f] / 60 * (sx / period), sy - gap * (a - 1) + .8,
+         (dep1[f] mod 1440) div 60, (dep1[f] mod 1440) mod 60,
+         dest[f] >> file;
+      printf "%.3f %.3f moveto (%d %02d:%02d) dup show\n",
+         dep1[f] / 60 * (sx / period), sy - gap * (a - 1) - 2.1,
+         fno1[f],
+         (arr2[f] mod 1440) div 60, (arr2[f] mod 1440) mod 60 >> file;
+   }
+}
+
+printf "showpage\n" >> file;
+printf "%%%%EOF\n" >> file;
+
+########################################################################
+
+data;
+
+param title := "Tu-154 [from 2008-08-18 to 2008-08-24]";
+
+param nf := 261;
+
+param : hub dest fno1 dep1  arr1  fno2 dep2  arr2 :=
+      1  1  IKT  743   195   520  744   610   970
+      2  1  OMS  815   205   405  816   485   700
+      3  1  CEK  897   205   360  898   430   595
+      4  1  KRR  763   260   400  764   480   610
+      5  2  SIP  133   280   420  134   500   620
+      6  2  BUD  131   290   450  132   520   675
+      7  1  AAQ  701   305   440  702   510   640
+      8  1  MRV  785   310   440  786   520   650
+      9  2  WAW  101   355   475  102   540   660
+     10  2  GYD  147   370   550  148   675   860
+     11  1  AER  869   385   530  870   655   795
+     12  1  KRR  765   430   560  766   630   760
+     13  1  AAQ  703   520   660  704   740   850
+     14  1  LED  845   530   620  846   690   775
+     15  1  KRR  767   540   675  768   765   895
+     16  2  KBP  183   665   760  184   850   940
+     17  1  MRV  787   755   905  788   985  1135
+     18  1  KRR  771   810   940  772  1030  1165
+     19  1  LED  849   825   900  850   960  1095
+     20  2  IST  209   880  1050  210  1120  1280
+     21  1  AER  873   885  1030  874  1760  1900
+     22  1  ASF  711   995  1145  712  1640  1795
+     23  2  ULN  563   995  1335  564  1415  1815
+     24  2  OTP  151  1020  1175  152  1800  1940
+     25  2  BEY  509  1025  1265  510  1350  1580
+     26  2  OSL  211  1060  1220  212  1860  2015
+     27  1  IKT  739  1085  1420  740  1510  1870
+     28  1  KRR  773  1095  1240  774  1620  1765
+     29  1  SGC  877  1120  1315  878  1395  1625
+     30  1  LED  857  1150  1230  858  1610  1690
+     31  1  CEK  899  1230  1385  900  1455  1620
+     32  1  PEE  821  1235  1390  822  1450  1600
+     33  2  TBS  197  1240  1405  198  1560  1715
+     34  1  UFA  891  1275  1405  892  1475  1610
+     35  1  KJA  781  1300  1570  782  1680  1990
+     36  1  IKT  743  1635  1960  744  2050  2410
+     37  1  OMS  815  1645  1845  816  1925  2140
+     38  1  CEK  897  1645  1800  898  1870  2035
+     39  1  KRR  763  1700  1840  764  1920  2050
+     40  2  SIP  133  1720  1860  134  1940  2060
+     41  2  BUD  131  1730  1890  132  1960  2115
+     42  1  AAQ  701  1745  1880  702  1950  2080
+     43  1  MRV  785  1750  1880  786  1960  2090
+     44  2  WAW  101  1795  1915  102  1980  2100
+     45  2  GYD  147  1810  1990  148  2115  2300
+     46  1  AER  869  1825  1970  870  2095  2235
+     47  2  EVN  193  1850  2030  194  2105  2275
+     48  1  KRR  765  1870  2000  766  2070  2200
+     49  1  AAQ  703  1960  2100  704  2180  2290
+     50  1  LED  845  1970  2060  846  2130  2215
+     51  1  KRR  767  1980  2115  768  2205  2335
+     52  2  KBP  183  2105  2200  184  2290  2380
+     53  1  MRV  787  2195  2345  788  2425  2575
+     54  1  KRR  771  2250  2380  772  2470  2605
+     55  1  LED  849  2265  2340  850  2400  2535
+     56  2  IST  209  2320  2490  210  2560  2720
+     57  1  AER  873  2325  2470  874  3200  3340
+     58  2  ULN  563  2435  2775  564  2855  3255
+     59  1  ASF  711  2435  2585  712  3080  3235
+     60  2  DAM  517  2465  2705  518  2790  3020
+     61  2  OSL  211  2500  2660  212  3300  3455
+     62  2  KBP  185  2510  2610  186  3160  3250
+     63  1  IKT  739  2525  2860  740  2950  3310
+     64  1  KRR  773  2535  2680  774  3060  3205
+     65  1  SGC  877  2560  2755  878  2835  3065
+     66  1  LED  857  2590  2670  858  3050  3130
+     67  1  CEK  899  2670  2825  900  2895  3060
+     68  1  PEE  821  2675  2830  822  2890  3040
+     69  2  TBS  197  2680  2845  198  3000  3155
+     70  1  UFA  891  2715  2845  892  2915  3050
+     71  1  KJA  781  2740  3010  782  3120  3430
+     72  1  IKT  743  3075  3400  744  3490  3850
+     73  1  CEK  897  3085  3240  898  3310  3475
+     74  1  OMS  815  3085  3285  816  3365  3580
+     75  1  KRR  763  3140  3280  764  3360  3490
+     76  2  SIP  133  3160  3300  134  3380  3500
+     77  2  BUD  131  3170  3330  132  3400  3555
+     78  1  AAQ  701  3185  3320  702  3390  3520
+     79  1  MRV  785  3190  3320  786  3400  3530
+     80  2  WAW  101  3235  3355  102  3420  3540
+     81  2  FRU  181  3245  3495  182  3590  3860
+     82  2  GYD  147  3250  3430  148  3555  3740
+     83  1  AER  869  3265  3410  870  3535  3675
+     84  1  KRR  765  3310  3440  766  3510  3640
+     85  1  AAQ  703  3400  3540  704  3620  3730
+     86  1  LED  845  3410  3500  846  3570  3655
+     87  1  KRR  767  3420  3555  768  3645  3775
+     88  2  KBP  183  3545  3640  184  3730  3820
+     89  1  MRV  787  3635  3785  788  3865  4015
+     90  1  KRR  771  3690  3820  772  3910  4045
+     91  1  LED  849  3705  3780  850  3840  3975
+     92  2  IST  209  3760  3930  210  4000  4160
+     93  1  AER  873  3765  3910  874  4640  4780
+     94  2  ULN  563  3875  4215  564  4295  4695
+     95  1  ASF  711  3875  4025  712  4520  4675
+     96  2  OTP  151  3900  4055  152  4680  4820
+     97  2  BEY  509  3905  4145  510  4230  4460
+     98  2  OSL  211  3940  4100  212  4740  4895
+     99  2  KBP  185  3950  4050  186  4600  4690
+    100  1  IKT  739  3965  4300  740  4390  4750
+    101  1  KRR  773  3975  4120  774  4500  4645
+    102  1  SGC  877  4000  4195  878  4275  4505
+    103  1  LED  857  4030  4110  858  4490  4570
+    104  1  CEK  899  4110  4265  900  4335  4500
+    105  1  PEE  821  4115  4270  822  4330  4480
+    106  2  TBS  197  4120  4285  198  4440  4595
+    107  1  UFA  891  4155  4285  892  4355  4490
+    108  1  KJA  781  4180  4450  782  4560  4870
+    109  1  IKT  743  4515  4840  744  4930  5290
+    110  1  OMS  815  4525  4725  816  4805  5020
+    111  1  CEK  897  4525  4680  898  4750  4915
+    112  1  KRR  763  4580  4720  764  4800  4930
+    113  2  SIP  133  4600  4740  134  4820  4940
+    114  2  BUD  131  4610  4770  132  4840  4995
+    115  1  AAQ  701  4625  4760  702  4830  4960
+    116  1  MRV  785  4630  4760  786  4840  4970
+    117  2  WAW  101  4675  4795  102  4860  4980
+    118  2  GYD  147  4690  4870  148  4995  5180
+    119  1  AER  869  4705  4850  870  4975  5115
+    120  2  EVN  193  4730  4910  194  4985  5155
+    121  1  KRR  765  4750  4880  766  4950  5080
+    122  1  AAQ  703  4840  4980  704  5060  5170
+    123  1  LED  845  4850  4940  846  5010  5095
+    124  1  KRR  767  4860  4995  768  5085  5215
+    125  2  KBP  183  4985  5080  184  5170  5260
+    126  1  MRV  787  5075  5225  788  5305  5455
+    127  1  KRR  771  5130  5260  772  5350  5485
+    128  1  LED  849  5145  5220  850  5280  5415
+    129  2  IST  209  5200  5370  210  5440  5600
+    130  1  AER  873  5205  5350  874  6080  6220
+    131  1  ASF  711  5315  5465  712  5960  6115
+    132  2  ULN  563  5315  5655  564  5735  6135
+    133  2  DAM  517  5345  5585  518  5670  5900
+    134  2  OSL  211  5380  5540  212  6180  6335
+    135  2  KBP  185  5390  5490  186  6040  6130
+    136  1  IKT  739  5405  5740  740  5830  6190
+    137  1  KRR  773  5415  5560  774  5940  6085
+    138  1  SGC  877  5440  5635  878  5715  5945
+    139  1  LED  857  5470  5550  858  5930  6010
+    140  1  CEK  899  5550  5705  900  5775  5940
+    141  1  PEE  821  5555  5710  822  5770  5920
+    142  2  TBS  197  5560  5725  198  5880  6035
+    143  1  UFA  891  5595  5725  892  5795  5930
+    144  1  KJA  781  5620  5890  782  6000  6310
+    145  1  IKT  743  5955  6280  744  6370  6730
+    146  1  OMS  815  5965  6165  816  6245  6460
+    147  1  CEK  897  5965  6120  898  6190  6355
+    148  1  KRR  763  6020  6160  764  6240  6370
+    149  2  SIP  133  6040  6180  134  6260  6380
+    150  2  BUD  131  6050  6210  132  6280  6435
+    151  1  AAQ  701  6065  6200  702  6270  6400
+    152  1  MRV  785  6070  6200  786  6280  6410
+    153  2  WAW  101  6115  6235  102  6300  6420
+    154  2  FRU  181  6125  6375  182  6470  6740
+    155  2  GYD  147  6130  6310  148  6435  6620
+    156  1  AER  869  6145  6290  870  6415  6555
+    157  2  EVN  193  6170  6350  194  6425  6595
+    158  1  KRR  765  6190  6320  766  6390  6520
+    159  1  AAQ  703  6280  6420  704  6500  6610
+    160  1  LED  845  6290  6380  846  6450  6535
+    161  1  KRR  767  6300  6435  768  6525  6655
+    162  2  KBP  183  6425  6520  184  6610  6700
+    163  2  AYT  223  6500  6690  224  6750  6940
+    164  1  AER  867  6510  6660  868  6730  6880
+    165  1  MRV  787  6515  6665  788  6745  6895
+    166  1  KRR  771  6570  6700  772  6790  6925
+    167  1  LED  849  6585  6660  850  6720  6855
+    168  2  IST  209  6640  6810  210  6880  7040
+    169  1  AER  873  6645  6790  874  7520  7660
+    170  1  ASF  711  6755  6905  712  7400  7555
+    171  2  ULN  563  6755  7095  564  7175  7575
+    172  2  OTP  151  6780  6935  152  7560  7700
+    173  2  BEY  509  6785  7025  510  7110  7340
+    174  2  OSL  211  6820  6980  212  7620  7775
+    175  2  KBP  185  6830  6930  186  7480  7570
+    176  1  IKT  739  6845  7180  740  7270  7630
+    177  1  KRR  773  6855  7000  774  7380  7525
+    178  1  SGC  877  6880  7075  878  7155  7385
+    179  1  LED  857  6910  6990  858  7370  7450
+    180  1  CEK  899  6990  7145  900  7215  7380
+    181  1  PEE  821  6995  7150  822  7210  7360
+    182  2  TBS  197  7000  7165  198  7320  7475
+    183  1  UFA  891  7035  7165  892  7235  7370
+    184  1  KJA  781  7060  7330  782  7440  7750
+    185  1  IKT  743  7395  7720  744  7810  8170
+    186  1  CEK  897  7405  7560  898  7630  7795
+    187  1  KRR  763  7460  7600  764  7680  7810
+    188  2  SIP  133  7480  7620  134  7700  7820
+    189  2  BUD  131  7490  7650  132  7720  7875
+    190  1  AAQ  701  7505  7640  702  7710  7840
+    191  1  MRV  785  7510  7640  786  7720  7850
+    192  2  IST  207  7545  7720  208  7795  7985
+    193  2  WAW  101  7555  7675  102  7740  7860
+    194  2  GYD  147  7570  7750  148  7875  8060
+    195  1  AER  869  7585  7730  870  7855  7995
+    196  2  AYT  221  7610  7800  222  7895  8085
+    197  2  EVN  193  7610  7790  194  7865  8035
+    198  1  KRR  765  7630  7760  766  7830  7960
+    199  1  AAQ  703  7720  7860  704  7940  8050
+    200  1  LED  845  7730  7820  846  7890  7975
+    201  1  KRR  767  7740  7875  768  7965  8095
+    202  2  KBP  183  7865  7960  184  8050  8140
+    203  2  AYT  223  7940  8130  224  8190  8380
+    204  1  MRV  787  7955  8105  788  8185  8335
+    205  1  KRR  771  8010  8140  772  8230  8365
+    206  1  LED  849  8025  8100  850  8160  8295
+    207  2  IST  209  8080  8250  210  8320  8480
+    208  1  AER  873  8085  8230  874  8960  9100
+    209  1  ASF  711  8195  8345  712  8840  8995
+    210  2  ULN  563  8195  8535  564  8615  9015
+    211  1  KJA  779  8230  8500  780  8575  8870
+    212  2  OSL  211  8260  8420  212  9060  9215
+    213  2  KBP  185  8270  8370  186  8920  9010
+    214  1  IKT  739  8285  8620  740  8710  9070
+    215  1  KRR  773  8295  8440  774  8820  8965
+    216  1  SGC  877  8320  8515  878  8595  8825
+    217  1  LED  857  8350  8430  858  8810  8890
+    218  1  CEK  899  8430  8585  900  8655  8820
+    219  1  PEE  821  8435  8590  822  8650  8800
+    220  2  TBS  197  8440  8605  198  8760  8915
+    221  1  UFA  891  8475  8605  892  8675  8810
+    222  1  KJA  781  8500  8770  782  8880  9190
+    223  1  IKT  743  8835  9160  744  9250  9610
+    224  1  OMS  815  8845  9045  816  9125  9340
+    225  1  CEK  897  8845  9000  898  9070  9235
+    226  1  KRR  763  8900  9040  764  9120  9250
+    227  2  SIP  133  8920  9060  134  9140  9260
+    228  2  BUD  131  8930  9090  132  9160  9315
+    229  1  AAQ  701  8945  9080  702  9150  9280
+    230  1  MRV  785  8950  9080  786  9160  9290
+    231  2  IST  207  8985  9160  208  9235  9425
+    232  2  WAW  101  8995  9115  102  9180  9300
+    233  2  FRU  181  9005  9255  182  9350  9620
+    234  2  GYD  147  9010  9190  148  9315  9500
+    235  1  AER  869  9025  9170  870  9295  9435
+    236  2  EVN  193  9050  9230  194  9305  9475
+    237  1  KRR  765  9070  9200  766  9270  9400
+    238  1  AAQ  703  9160  9300  704  9380  9490
+    239  1  LED  845  9170  9260  846  9330  9415
+    240  1  KRR  767  9180  9315  768  9405  9535
+    241  2  KBP  183  9305  9400  184  9490  9580
+    242  2  AYT  223  9380  9570  224  9630  9820
+    243  1  MRV  787  9395  9545  788  9625  9775
+    244  1  KRR  771  9450  9580  772  9670  9805
+    245  1  LED  849  9465  9540  850  9600  9735
+    246  2  IST  209  9520  9690  210  9760  9920
+    247  1  AER  873  9525  9670  874 10400 10540
+    248  1  ASF  711  9635  9785  712 10280 10435
+    249  2  ULN  563  9635  9975  564 10055 10455
+    250  2  OTP  151  9660  9815  152 10440 10580
+    251  2  DAM  517  9665  9905  518  9990 10220
+    252  2  OSL  211  9700  9860  212 10500 10655
+    253  2  KBP  185  9710  9810  186 10360 10450
+    254  1  IKT  739  9725 10060  740 10150 10510
+    255  1  KRR  773  9735  9880  774 10260 10405
+    256  1  SGC  877  9760  9955  878 10035 10265
+    257  1  LED  857  9790  9870  858 10250 10330
+    258  1  CEK  899  9870 10025  900 10095 10260
+    259  1  PEE  821  9875 10030  822 10090 10240
+    260  1  UFA  891  9915 10045  892 10115 10250
+    261  1  KJA  781  9940 10210  782 10320 10630
+;
+
+end;
Index: deps/glpk/examples/todd.mod
===================================================================
--- deps/glpk/examples/todd.mod	(revision 9)
+++ deps/glpk/examples/todd.mod	(revision 9)
@@ -0,0 +1,36 @@
+/* TODD, a class of hard instances of zero-one knapsack problems */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* Chvatal describes a class of instances of zero-one knapsack problems
+   due to Todd. He shows that a wide class of algorithms - including all
+   based on branch and bound or dynamic programming - find it difficult
+   to solve problems in the Todd class. More exactly, the time required
+   by these algorithms to solve instances of problems that belong to the
+   Todd class grows as an exponential function of the problem size.
+
+   Reference:
+   Chvatal V. (1980), Hard knapsack problems, Op. Res. 28, 1402-1411. */
+
+param n > 0 integer;
+
+param log2_n := log(n) / log(2);
+
+param k := floor(log2_n);
+
+param a{j in 1..n} := 2 ** (k + n + 1) + 2 ** (k + n + 1 - j) + 1;
+
+param b := 0.5 * floor(sum{j in 1..n} a[j]);
+
+var x{1..n} binary;
+
+maximize obj: sum{j in 1..n} a[j] * x[j];
+
+s.t. cap: sum{j in 1..n} a[j] * x[j] <= b;
+
+data;
+
+param n := 15;
+/* change this parameter to choose a particular instance */
+
+end;
Index: deps/glpk/examples/train.mod
===================================================================
--- deps/glpk/examples/train.mod	(revision 9)
+++ deps/glpk/examples/train.mod	(revision 9)
@@ -0,0 +1,281 @@
+# TRAIN, a model of railroad passenger car allocation
+#
+# References:
+# Robert Fourer, David M. Gay and Brian W. Kernighan, "A Modeling Language
+# for Mathematical Programming." Management Science 36 (1990) 519-554.
+
+###  SCHEDULE SETS AND PARAMETERS  ###
+
+set cities;
+
+set links within {c1 in cities, c2 in cities: c1 <> c2};
+
+                        # Set of cities, and set of intercity links
+
+param last > 0 integer; # Number of time intervals in a day
+
+set times := 1..last;   # Set of time intervals in a day
+
+set schedule within
+      {c1 in cities, t1 in times,
+       c2 in cities, t2 in times: (c1,c2) in links};
+
+                        # Member (c1,t1,c2,t2) of this set represents
+                        # a train that leaves city c1 at time t1
+                        # and arrives in city c2 at time t2
+
+###  DEMAND PARAMETERS  ###
+
+param section > 0 integer;
+
+                        # Maximum number of cars in one section of a train
+
+param demand {schedule} > 0;
+
+                        # For each scheduled train:
+                        # the smallest number of cars that
+                        # can meet demand for the train
+
+param low {(c1,t1,c2,t2) in schedule} := ceil(demand[c1,t1,c2,t2]);
+
+                        # Minimum number of cars needed to meet demand
+
+param high {(c1,t1,c2,t2) in schedule}
+
+   := max (2, min (ceil(2*demand[c1,t1,c2,t2]),
+                   section*ceil(demand[c1,t1,c2,t2]/section) ));
+
+                        # Maximum number of cars allowed on a train:
+                        # 2 if demand is for less than one car;
+                        # otherwise, lesser of
+                        # number of cars needed to hold twice the demand, and
+                        # number of cars in minimum number of sections needed
+
+###  DISTANCE PARAMETERS  ###
+
+param dist_table {links} >= 0 default 0.0;
+
+param distance {(c1,c2) in links} > 0
+   := if dist_table[c1,c2] > 0 then dist_table[c1,c2] else dist_table[c2,c1];
+
+                        # Inter-city distances: distance[c1,c2] is miles
+                        # between city c1 and city c2
+
+###  VARIABLES  ###
+
+var U 'cars stored' {cities,times} >= 0;
+
+                        # u[c,t] is the number of unused cars stored
+                        # at city c in the interval beginning at time t
+
+var X 'cars in train' {schedule} >= 0;
+
+                        # x[c1,t1,c2,t2] is the number of cars assigned to
+                        # the scheduled train that leaves c1 at t1 and
+                        # arrives in c2 at t2
+
+###  OBJECTIVES  ###
+
+minimize cars:
+       sum {c in cities} U[c,last] +
+       sum {(c1,t1,c2,t2) in schedule: t2 < t1} X[c1,t1,c2,t2];
+
+                        # Number of cars in the system:
+                        # sum of unused cars and cars in trains during
+                        # the last time interval of the day
+
+minimize miles:
+       sum {(c1,t1,c2,t2) in schedule} distance[c1,c2] * X[c1,t1,c2,t2];
+
+                        # Total car-miles run by all scheduled trains in a day
+
+###  CONSTRAINTS  ###
+
+account {c in cities, t in times}:
+
+  U[c,t] = U[c, if t > 1 then t-1 else last] +
+
+      sum {(c1,t1,c,t) in schedule} X[c1,t1,c,t] -
+      sum {(c,t,c2,t2) in schedule} X[c,t,c2,t2];
+
+                        # For every city and time:
+                        # unused cars in the present interval must equal
+                        # unused cars in the previous interval,
+                        # plus cars just arriving in trains,
+                        # minus cars just leaving in trains
+
+satisfy {(c1,t1,c2,t2) in schedule}:
+
+       low[c1,t1,c2,t2] <= X[c1,t1,c2,t2] <= high[c1,t1,c2,t2];
+
+                        # For each scheduled train:
+                        # number of cars must meet demand,
+                        # but must not be so great that unnecessary
+                        # sections are run
+
+###  DATA  ###
+
+data;
+
+set cities := BO NY PH WA ;
+
+set links := (BO,NY) (NY,PH) (PH,WA)
+             (NY,BO) (PH,NY) (WA,PH) ;
+
+param dist_table := [*,*]  BO NY  232
+                           NY PH   90
+                           PH WA  135 ;
+
+param last := 48 ;
+
+param section := 14 ;
+
+set schedule :=
+
+   (WA,*,PH,*)   2  5     6  9     8 11    10 13
+                12 15    13 16    14 17    15 18
+                16 19    17 20    18 21    19 22
+                20 23    21 24    22 25    23 26
+                24 27    25 28    26 29    27 30
+                28 31    29 32    30 33    31 34
+                32 35    33 36    34 37    35 38
+                36 39    37 40    38 41    39 42
+                40 43    41 44    42 45    44 47
+                46  1
+
+   (PH,*,NY,*)   1  3     5  7     9 11    11 13
+                13 15    14 16    15 17    16 18
+                17 19    18 20    19 21    20 22
+                21 23    22 24    23 25    24 26
+                25 27    26 28    27 29    28 30
+                29 31    30 32    31 33    32 34
+                33 35    34 36    35 37    36 38
+                37 39    38 40    39 41    40 42
+                41 43    42 44    43 45    44 46
+                45 47    47  1
+
+   (NY,*,BO,*)  10 16    12 18    14 20    15 21
+                16 22    17 23    18 24    19 25
+                20 26    21 27    22 28    23 29
+                24 30    25 31    26 32    27 33
+                28 34    29 35    30 36    31 37
+                32 38    33 39    34 40    35 41
+                36 42    37 43    38 44    39 45
+                40 46    41 47    42 48    43  1
+                44  2    45  3    46  4    48  6
+
+   (BO,*,NY,*)   7 13     9 15    11 17    12 18
+                13 19    14 20    15 21    16 22
+                17 23    18 24    19 25    20 26
+                21 27    22 28    23 29    24 30
+                25 31    26 32    27 33    28 34
+                29 35    30 36    31 37    32 38
+                33 39    34 40    35 41    36 42
+                37 43    38 44    39 45    40 46
+                41 47    43  1    45  3    47  5
+
+   (NY,*,PH,*)   1  3    12 14    13 15    14 16
+                15 17    16 18    17 19    18 20
+                19 21    20 22    21 23    22 24
+                23 25    24 26    25 27    26 28
+                27 29    28 30    29 31    30 32
+                31 33    32 34    33 35    34 36
+                35 37    36 38    37 39    38 40
+                39 41    40 42    41 43    42 44
+                43 45    44 46    45 47    46 48
+                47  1
+
+   (PH,*,WA,*)   1  4    14 17    15 18    16 19
+                17 20    18 21    19 22    20 23
+                21 24    22 25    23 26    24 27
+                25 28    26 29    27 30    28 31
+                29 32    30 33    31 34    32 35
+                33 36    34 37    35 38    36 39
+                37 40    38 41    39 42    40 43
+                41 44    42 45    43 46    44 47
+                45 48    46  1    47  2    ;
+
+param demand :=
+
+ [WA,*,PH,*]   2  5    .55      6  9    .01      8 11    .01
+              10 13    .13     12 15   1.59     13 16   1.69
+              14 17   5.19     15 18   3.55     16 19   6.29
+              17 20   4.00     18 21   5.80     19 22   3.40
+              20 23   4.88     21 24   2.92     22 25   4.37
+              23 26   2.80     24 27   4.23     25 28   2.88
+              26 29   4.33     27 30   3.11     28 31   4.64
+              29 32   3.44     30 33   4.95     31 34   3.73
+              32 35   5.27     33 36   3.77     34 37   4.80
+              35 38   3.31     36 39   3.89     37 40   2.65
+              38 41   3.01     39 42   2.04     40 43   2.31
+              41 44   1.52     42 45   1.75     44 47   1.88
+              46  1   1.05
+
+ [PH,*,NY,*]   1  3   1.05      5  7    .43      9 11    .20
+              11 13    .21     13 15    .40     14 16   6.49
+              15 17  16.40     16 18   9.48     17 19  17.15
+              18 20   9.31     19 21  15.20     20 22   8.21
+              21 23  13.32     22 24   7.35     23 25  11.83
+              24 26   6.61     25 27  10.61     26 28   6.05
+              27 29   9.65     28 30   5.61     29 31   9.25
+              30 32   5.40     31 33   8.24     32 34   4.84
+              33 35   7.44     34 36   4.44     35 37   6.80
+              36 38   4.11     37 39   6.25     38 40   3.69
+              39 41   5.55     40 42   3.29     41 43   4.77
+              42 44   2.91     43 45   4.19     44 46   2.53
+              45 47   4.00     47 1    1.65
+
+ [NY,*,BO,*]  10 16   1.23     12 18   3.84     14 20   4.08
+              15 21   1.47     16 22   2.96     17 23   1.60
+              18 24   2.95     19 25   1.71     20 26   2.81
+              21 27   1.77     22 28   2.87     23 29   1.84
+              24 30   2.95     25 31   1.91     26 32   3.12
+              27 33   1.93     28 34   3.31     29 35   2.00
+              30 36   3.40     31 37   2.08     32 38   3.41
+              33 39   2.69     34 40   4.45     35 41   2.32
+              36 42   3.40     37 43   1.80     38 44   2.63
+              39 45   1.52     40 46   2.23     41 47   1.25
+              42 48   1.79     43  1    .97     44  2   1.28
+              45  3    .48     46  4    .68     48  6    .08
+
+ [BO,*,NY,*]   7 13    .03      9 15   1.29     11 17   4.59
+              12 18   2.56     13 19   3.92     14 20   2.37
+              15 21   3.81     16 22   2.24     17 23   3.51
+              18 24   2.13     19 25   3.28     20 26   2.05
+              21 27   3.15     22 28   1.99     23 29   3.09
+              24 30   1.93     25 31   3.19     26 32   1.91
+              27 33   3.21     28 34   1.85     29 35   3.21
+              30 36   1.71     31 37   3.04     32 38   2.08
+              33 39   3.13     34 40   1.96     35 41   2.53
+              36 42   1.43     37 43   2.04     38 44   1.12
+              39 45   1.71     40 46    .91     41 47   1.32
+              43  1   1.80     45  3   1.13     47  5    .23
+
+ [NY,*,PH,*]   1  3    .04     12 14   4.68     13 15   5.61
+              14 16   3.56     15 17   5.81     16 18   3.81
+              17 19   6.31     18 20   4.07     19 21   7.33
+              20 22   4.55     21 23   7.37     22 24   4.73
+              23 25   7.61     24 26   4.92     25 27   7.91
+              26 28   5.19     27 29   8.40     28 30   5.53
+              29 31   9.32     30 32   5.51     31 33  10.33
+              32 34   9.21     33 35  18.95     34 36  11.23
+              35 37  16.85     36 38   7.29     37 39  10.89
+              38 40   5.41     39 41   8.21     40 42   4.52
+              41 43   6.99     42 44   3.92     43 45   6.21
+              44 46   3.44     45 47   5.17     46 48   2.55
+              47  1   1.24
+
+ [PH,*,WA,*]   1  4    .20     14 17   4.49     15 18   3.53
+              16 19   2.67     17 20   3.83     18 21   3.01
+              19 22   4.12     20 23   3.15     21 24   4.67
+              22 25   3.20     23 26   4.23     24 27   2.87
+              25 28   3.84     26 29   2.60     27 30   3.80
+              28 31   2.77     29 32   4.31     30 33   3.16
+              31 34   4.88     32 35   3.45     33 36   5.55
+              34 37   3.52     35 38   6.11     36 39   3.32
+              37 40   5.53     38 41   3.03     39 42   4.51
+              40 43   2.53     41 44   3.39     42 45   1.93
+              43 46   2.52     44 47   1.20     45 48   1.75
+              46  1    .88     47  2    .87     ;
+
+end;
Index: deps/glpk/examples/transp.mod
===================================================================
--- deps/glpk/examples/transp.mod	(revision 9)
+++ deps/glpk/examples/transp.mod	(revision 9)
@@ -0,0 +1,63 @@
+# A TRANSPORTATION PROBLEM
+#
+# This problem finds a least cost shipping schedule that meets
+# requirements at markets and supplies at factories.
+#
+#  References:
+#              Dantzig G B, "Linear Programming and Extensions."
+#              Princeton University Press, Princeton, New Jersey, 1963,
+#              Chapter 3-3.
+
+set I;
+/* canning plants */
+
+set J;
+/* markets */
+
+param a{i in I};
+/* capacity of plant i in cases */
+
+param b{j in J};
+/* demand at market j in cases */
+
+param d{i in I, j in J};
+/* distance in thousands of miles */
+
+param f;
+/* freight in dollars per case per thousand miles */
+
+param c{i in I, j in J} := f * d[i,j] / 1000;
+/* transport cost in thousands of dollars per case */
+
+var x{i in I, j in J} >= 0;
+/* shipment quantities in cases */
+
+minimize cost: sum{i in I, j in J} c[i,j] * x[i,j];
+/* total transportation costs in thousands of dollars */
+
+s.t. supply{i in I}: sum{j in J} x[i,j] <= a[i];
+/* observe supply limit at plant i */
+
+s.t. demand{j in J}: sum{i in I} x[i,j] >= b[j];
+/* satisfy demand at market j */
+
+data;
+
+set I := Seattle San-Diego;
+
+set J := New-York Chicago Topeka;
+
+param a := Seattle     350
+           San-Diego   600;
+
+param b := New-York    325
+           Chicago     300
+           Topeka      275;
+
+param d :              New-York   Chicago   Topeka :=
+           Seattle     2.5        1.7       1.8
+           San-Diego   2.5        1.8       1.4  ;
+
+param f := 90;
+
+end;
Index: deps/glpk/examples/trick.mod
===================================================================
--- deps/glpk/examples/trick.mod	(revision 9)
+++ deps/glpk/examples/trick.mod	(revision 9)
@@ -0,0 +1,72 @@
+/* TRICK, A Transportation Design Problem */
+
+/* Translated from the Mosel modeling language to GNU MathProg by
+   Andrew Makhorin <mao@gnu.org> */
+
+/* This example model is described in the article "Formulations and
+   Reformulations in Integer Programming" by Michael Trick (it is
+   publicly available at http://mat.gsia.cmu.edu/trick/formul04.pdf).
+
+   This model demonstrates an amazing effect when including in the
+   formulation an additional constraint, which is redundant even for
+   LP relaxation, makes the model easy for solving with the B&B. */
+
+set TRUCKS := 1..10;
+
+set PACKAGES := 1..20;
+
+param capacity{TRUCKS};
+
+param size{PACKAGES};
+
+param cost{TRUCKS};
+
+param can_use{PACKAGES, TRUCKS};
+
+var x{PACKAGES, TRUCKS}, binary;
+
+var y{TRUCKS}, binary;
+
+minimize total: sum{i in TRUCKS} cost[i] * y[i];
+
+f1{i in TRUCKS}:
+      sum{j in PACKAGES} size[j] * x[j,i] <= capacity[i] * y[i];
+
+f2{i in TRUCKS, j in PACKAGES}:
+      x[j,i] <= y[i];
+
+f3{j in PACKAGES}:
+      sum{i in TRUCKS} can_use[j,i] * x[j,i] = 1;
+
+redundant_constraint:
+      sum{i in TRUCKS} capacity[i] * y[i] >= sum{j in PACKAGES} size[j];
+
+data;
+
+param capacity :=
+      [1] 100 [2] 200 [3] 100 [4] 200 [5] 100 [6] 200 [7] 100 [8] 200
+      [9] 100 [10] 200;
+
+param size :=
+      [1] 17 [2] 21 [3] 54 [4] 45 [5] 87 [6] 34 [7] 23 [8] 45 [9] 12
+      [10] 43 [11] 54 [12] 39 [13] 31 [14] 26 [15] 75 [16] 48 [17] 16
+      [18] 32 [19] 45 [20] 55;
+
+param cost :=
+      [1] 1 [2] 1.8 [3] 1 [4] 1.8 [5] 1 [6] 1.8 [7] 1 [8] 1.8 [9] 1
+      [10] 1.8;
+
+param can_use (tr):
+      1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 :=
+   1  1  1  1  1  1  1  0  0  0  0  1  1  1  1  0  0  0  0  0  0
+   2  1  1  1  1  1  1  1  1  0  0  1  1  1  1  1  1  1  0  0  0
+   3  0  1  1  1  1  0  0  0  0  0  0  1  1  1  1  1  1  0  0  0
+   4  0  0  1  1  1  1  1  1  1  1  0  0  1  1  1  1  1  1  0  0
+   5  0  0  1  1  1  1  0  0  0  0  0  0  0  1  1  1  1  1  1  0
+   6  0  0  0  1  1  1  1  0  0  0  0  0  0  1  1  1  0  0  0  0
+   7  0  0  0  0  1  1  1  1  1  0  0  0  0  0  1  1  1  1  0  0
+   8  0  0  0  0  1  1  1  1  1  1  0  0  0  0  0  1  1  1  1  1
+   9  0  0  0  0  0  1  1  1  1  0  0  0  0  0  0  0  1  1  1  1
+  10  0  0  0  0  0  0  0  1  1  1  0  0  0  0  0  0  0  0  1  1;
+
+end;
Index: deps/glpk/examples/tsp.mod
===================================================================
--- deps/glpk/examples/tsp.mod	(revision 9)
+++ deps/glpk/examples/tsp.mod	(revision 9)
@@ -0,0 +1,335 @@
+/* TSP, Traveling Salesman Problem */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+/* The Traveling Salesman Problem (TSP) is stated as follows.
+   Let a directed graph G = (V, E) be given, where V = {1, ..., n} is
+   a set of nodes, E <= V x V is a set of arcs. Let also each arc
+   e = (i,j) be assigned a number c[i,j], which is the length of the
+   arc e. The problem is to find a closed path of minimal length going
+   through each node of G exactly once. */
+
+param n, integer, >= 3;
+/* number of nodes */
+
+set V := 1..n;
+/* set of nodes */
+
+set E, within V cross V;
+/* set of arcs */
+
+param c{(i,j) in E};
+/* distance from node i to node j */
+
+var x{(i,j) in E}, binary;
+/* x[i,j] = 1 means that the salesman goes from node i to node j */
+
+minimize total: sum{(i,j) in E} c[i,j] * x[i,j];
+/* the objective is to make the path length as small as possible */
+
+s.t. leave{i in V}: sum{(i,j) in E} x[i,j] = 1;
+/* the salesman leaves each node i exactly once */
+
+s.t. enter{j in V}: sum{(i,j) in E} x[i,j] = 1;
+/* the salesman enters each node j exactly once */
+
+/* Constraints above are not sufficient to describe valid tours, so we
+   need to add constraints to eliminate subtours, i.e. tours which have
+   disconnected components. Although there are many known ways to do
+   that, I invented yet another way. The general idea is the following.
+   Let the salesman sells, say, cars, starting the travel from node 1,
+   where he has n cars. If we require the salesman to sell exactly one
+   car in each node, he will need to go through all nodes to satisfy
+   this requirement, thus, all subtours will be eliminated. */
+
+var y{(i,j) in E}, >= 0;
+/* y[i,j] is the number of cars, which the salesman has after leaving
+   node i and before entering node j; in terms of the network analysis,
+   y[i,j] is a flow through arc (i,j) */
+
+s.t. cap{(i,j) in E}: y[i,j] <= (n-1) * x[i,j];
+/* if arc (i,j) does not belong to the salesman's tour, its capacity
+   must be zero; it is obvious that on leaving a node, it is sufficient
+   to have not more than n-1 cars */
+
+s.t. node{i in V}:
+/* node[i] is a conservation constraint for node i */
+
+      sum{(j,i) in E} y[j,i]
+      /* summary flow into node i through all ingoing arcs */
+
+      + (if i = 1 then n)
+      /* plus n cars which the salesman has at starting node */
+
+      = /* must be equal to */
+
+      sum{(i,j) in E} y[i,j]
+      /* summary flow from node i through all outgoing arcs */
+
+      + 1;
+      /* plus one car which the salesman sells at node i */
+
+solve;
+
+printf "Optimal tour has length %d\n",
+   sum{(i,j) in E} c[i,j] * x[i,j];
+printf("From node   To node   Distance\n");
+printf{(i,j) in E: x[i,j]} "      %3d       %3d   %8g\n",
+   i, j, c[i,j];
+
+data;
+
+/* These data correspond to the symmetric instance ulysses16 from:
+
+   Reinelt, G.: TSPLIB - A travelling salesman problem library.
+   ORSA-Journal of the Computing 3 (1991) 376-84;
+   http://elib.zib.de/pub/Packages/mp-testdata/tsp/tsplib */
+
+/* The optimal solution is 6859 */
+
+param n := 16;
+
+param : E : c :=
+    1  2   509
+    1  3   501
+    1  4   312
+    1  5  1019
+    1  6   736
+    1  7   656
+    1  8    60
+    1  9  1039
+    1 10   726
+    1 11  2314
+    1 12   479
+    1 13   448
+    1 14   479
+    1 15   619
+    1 16   150
+    2  1   509
+    2  3   126
+    2  4   474
+    2  5  1526
+    2  6  1226
+    2  7  1133
+    2  8   532
+    2  9  1449
+    2 10  1122
+    2 11  2789
+    2 12   958
+    2 13   941
+    2 14   978
+    2 15  1127
+    2 16   542
+    3  1   501
+    3  2   126
+    3  4   541
+    3  5  1516
+    3  6  1184
+    3  7  1084
+    3  8   536
+    3  9  1371
+    3 10  1045
+    3 11  2728
+    3 12   913
+    3 13   904
+    3 14   946
+    3 15  1115
+    3 16   499
+    4  1   312
+    4  2   474
+    4  3   541
+    4  5  1157
+    4  6   980
+    4  7   919
+    4  8   271
+    4  9  1333
+    4 10  1029
+    4 11  2553
+    4 12   751
+    4 13   704
+    4 14   720
+    4 15   783
+    4 16   455
+    5  1  1019
+    5  2  1526
+    5  3  1516
+    5  4  1157
+    5  6   478
+    5  7   583
+    5  8   996
+    5  9   858
+    5 10   855
+    5 11  1504
+    5 12   677
+    5 13   651
+    5 14   600
+    5 15   401
+    5 16  1033
+    6  1   736
+    6  2  1226
+    6  3  1184
+    6  4   980
+    6  5   478
+    6  7   115
+    6  8   740
+    6  9   470
+    6 10   379
+    6 11  1581
+    6 12   271
+    6 13   289
+    6 14   261
+    6 15   308
+    6 16   687
+    7  1   656
+    7  2  1133
+    7  3  1084
+    7  4   919
+    7  5   583
+    7  6   115
+    7  8   667
+    7  9   455
+    7 10   288
+    7 11  1661
+    7 12   177
+    7 13   216
+    7 14   207
+    7 15   343
+    7 16   592
+    8  1    60
+    8  2   532
+    8  3   536
+    8  4   271
+    8  5   996
+    8  6   740
+    8  7   667
+    8  9  1066
+    8 10   759
+    8 11  2320
+    8 12   493
+    8 13   454
+    8 14   479
+    8 15   598
+    8 16   206
+    9  1  1039
+    9  2  1449
+    9  3  1371
+    9  4  1333
+    9  5   858
+    9  6   470
+    9  7   455
+    9  8  1066
+    9 10   328
+    9 11  1387
+    9 12   591
+    9 13   650
+    9 14   656
+    9 15   776
+    9 16   933
+   10  1   726
+   10  2  1122
+   10  3  1045
+   10  4  1029
+   10  5   855
+   10  6   379
+   10  7   288
+   10  8   759
+   10  9   328
+   10 11  1697
+   10 12   333
+   10 13   400
+   10 14   427
+   10 15   622
+   10 16   610
+   11  1  2314
+   11  2  2789
+   11  3  2728
+   11  4  2553
+   11  5  1504
+   11  6  1581
+   11  7  1661
+   11  8  2320
+   11  9  1387
+   11 10  1697
+   11 12  1838
+   11 13  1868
+   11 14  1841
+   11 15  1789
+   11 16  2248
+   12  1   479
+   12  2   958
+   12  3   913
+   12  4   751
+   12  5   677
+   12  6   271
+   12  7   177
+   12  8   493
+   12  9   591
+   12 10   333
+   12 11  1838
+   12 13    68
+   12 14   105
+   12 15   336
+   12 16   417
+   13  1   448
+   13  2   941
+   13  3   904
+   13  4   704
+   13  5   651
+   13  6   289
+   13  7   216
+   13  8   454
+   13  9   650
+   13 10   400
+   13 11  1868
+   13 12    68
+   13 14    52
+   13 15   287
+   13 16   406
+   14  1   479
+   14  2   978
+   14  3   946
+   14  4   720
+   14  5   600
+   14  6   261
+   14  7   207
+   14  8   479
+   14  9   656
+   14 10   427
+   14 11  1841
+   14 12   105
+   14 13    52
+   14 15   237
+   14 16   449
+   15  1   619
+   15  2  1127
+   15  3  1115
+   15  4   783
+   15  5   401
+   15  6   308
+   15  7   343
+   15  8   598
+   15  9   776
+   15 10   622
+   15 11  1789
+   15 12   336
+   15 13   287
+   15 14   237
+   15 16   636
+   16  1   150
+   16  2   542
+   16  3   499
+   16  4   455
+   16  5  1033
+   16  6   687
+   16  7   592
+   16  8   206
+   16  9   933
+   16 10   610
+   16 11  2248
+   16 12   417
+   16 13   406
+   16 14   449
+   16 15   636
+;
+
+end;
Index: deps/glpk/examples/xyacfs.mod
===================================================================
--- deps/glpk/examples/xyacfs.mod	(revision 9)
+++ deps/glpk/examples/xyacfs.mod	(revision 9)
@@ -0,0 +1,56 @@
+/*Extended Yet Another Curve Fitting Solution (The poor man's RMA)
+
+  An extension of yacfs.mod adding a Weight parameter:
+    When set to 1 the model produces best fit by least squares with all error in y and none in x (YonX);
+    When set to zero the model produces best fit by least squares with all error in x and none in y (XonY);
+    When set to 0.5 the model assumes equal error in x and y producing results similar to fitting by Reduced Major Axis Analysis.
+
+  Nigel_Galloway@operamail.com
+  November 5th., 2009
+*/
+set Sample;
+param Sx {z in Sample};
+param Sy {z in Sample};
+param Weight := 0.5;
+
+var a;
+var b;
+var p;
+var q;
+
+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];
+XonY2 :sum{z in Sample} q*Sy[z] + sum{z in Sample} p = sum{z in Sample} Sx[z];
+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];
+YonX2 :sum{z in Sample} a*Sx[z] + sum{z in Sample} b = sum{z in Sample} Sy[z];
+
+solve;
+
+param W := Weight*a + (1-Weight)*(1/q);
+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);
+
+data;
+
+param:
+Sample:   Sx    Sy :=
+  1         0    1
+  2       0.5  0.9
+  3         1  0.7
+  4       1.5  1.5
+  5       1.9    2
+  6       2.5  2.4
+  7         3  3.2
+  8       3.5    2
+  9         4  2.7
+ 10       4.5  3.5
+ 11         5    1
+ 12       5.5    4
+ 13         6  3.6
+ 14       6.6  2.7
+ 15         7  5.7
+ 16       7.6  4.6
+ 17       8.5    6
+ 18         9  6.8
+ 19        10  7.3
+;
+
+end;
Index: deps/glpk/examples/yacfs.mod
===================================================================
--- deps/glpk/examples/yacfs.mod	(revision 9)
+++ deps/glpk/examples/yacfs.mod	(revision 9)
@@ -0,0 +1,48 @@
+/*Yet Another Curve Fitting Solution
+
+  Obviously this solution produces the same answer
+  as examples/cflsq.mod
+
+  Nigel_Galloway@operamail.com
+  February 1st., 2009
+*/
+set Sample;
+param Sx {z in Sample};
+param Sy {z in Sample};
+
+var a;
+var b;
+
+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];
+equalz2 :sum{z in Sample} a*Sx[z] + sum{z in Sample} b = sum{z in Sample} Sy[z];
+
+solve;
+
+printf "\nbest linear fit is:\n\ty = %f %s %fx\n\n", b, if a < 0 then "-" else "+", abs(a);
+
+data;
+
+param:
+Sample:   Sx    Sy :=
+  1         0    1
+  2       0.5  0.9
+  3         1  0.7
+  4       1.5  1.5
+  5       1.9    2
+  6       2.5  2.4
+  7         3  3.2
+  8       3.5    2
+  9         4  2.7
+ 10       4.5  3.5
+ 11         5    1
+ 12       5.5    4
+ 13         6  3.6
+ 14       6.6  2.7
+ 15         7  5.7
+ 16       7.6  4.6
+ 17       8.5    6
+ 18         9  6.8
+ 19        10  7.3
+;
+
+end;
Index: deps/glpk/examples/zebra.mod
===================================================================
--- deps/glpk/examples/zebra.mod	(revision 9)
+++ deps/glpk/examples/zebra.mod	(revision 9)
@@ -0,0 +1,151 @@
+/* ZEBRA, Who Owns the Zebra? */
+
+/* Written in GNU MathProg by Andrew Makhorin <mao@gnu.org> */
+
+########################################################################
+#  The Zebra Puzzle is a well-known logic puzzle.
+#
+#  It is often called "Einstein's Puzzle" or "Einstein's Riddle"
+#  because it is said to have been invented by Albert Einstein as a boy,
+#  with the common claim that Einstein said "only 2 percent of the
+#  world's population can solve". It is also sometimes attributed to
+#  Lewis Carroll. However, there is no known evidence for Einstein's or
+#  Carroll's authorship.
+#
+#  There are several versions of this puzzle. The version below is
+#  quoted from the first known publication in Life International
+#  magazine on December 17, 1962.
+#
+#   1. There are five houses.
+#   2. The Englishman lives in the red house.
+#   3. The Spaniard owns the dog.
+#   4. Coffee is drunk in the green house.
+#   5. The Ukrainian drinks tea.
+#   6. The green house is immediately to the right of the ivory house.
+#   7. The Old Gold smoker owns snails.
+#   8. Kools are smoked in the yellow house.
+#   9. Milk is drunk in the middle house.
+#  10. The Norwegian lives in the first house.
+#  11. The man who smokes Chesterfields lives in the house next to the
+#      man with the fox.
+#  12. Kools are smoked in the house next to the house where the horse
+#      is kept.
+#  13. The Lucky Strike smoker drinks orange juice.
+#  14. The Japanese smokes Parliaments.
+#  15. The Norwegian lives next to the blue house.
+#
+#  Now, who drinks water? Who owns the zebra?
+#
+#  In the interest of clarity, it must be added that each of the five
+#  houses is painted a different color, and their inhabitants are of
+#  different national extractions, own different pets, drink different
+#  beverages and smoke different brands of American cigarettes. One
+#  other thing: In statement 6, right means your right.
+#
+#  (From Wikipedia, the free encyclopedia.)
+########################################################################
+
+set HOUSE := { 1..5 };
+
+set COLOR := { "blue", "green", "ivory", "red", "yellow" };
+
+set NATIONALITY := { "Englishman", "Japanese", "Norwegian", "Spaniard",
+      "Ukranian" };
+
+set DRINK := { "coffee", "milk", "orange_juice", "tea", "water" };
+
+set SMOKE := { "Chesterfield", "Kools", "Lucky_Strike", "Old_Gold",
+      "Parliament" };
+
+set PET := { "dog", "fox", "horse", "snails", "zebra" };
+
+var color{HOUSE, COLOR}, binary;
+c1{h in HOUSE}: sum{c in COLOR} color[h,c] = 1;
+c2{c in COLOR}: sum{h in HOUSE} color[h,c] = 1;
+
+var nationality{HOUSE, NATIONALITY}, binary;
+n1{h in HOUSE}: sum{n in NATIONALITY} nationality[h,n] = 1;
+n2{n in NATIONALITY}: sum{h in HOUSE} nationality[h,n] = 1;
+
+var drink{HOUSE, DRINK}, binary;
+d1{h in HOUSE}: sum{d in DRINK} drink[h,d] = 1;
+d2{d in DRINK}: sum{h in HOUSE} drink[h,d] = 1;
+
+var smoke{HOUSE, SMOKE}, binary;
+s1{h in HOUSE}: sum{s in SMOKE} smoke[h,s] = 1;
+s2{s in SMOKE}: sum{h in HOUSE} smoke[h,s] = 1;
+
+var pet{HOUSE, PET}, binary;
+p1{h in HOUSE}: sum{p in PET} pet[h,p] = 1;
+p2{p in PET}: sum{h in HOUSE} pet[h,p] = 1;
+
+/* the Englishman lives in the red house */
+f2{h in HOUSE}: nationality[h,"Englishman"] = color[h,"red"];
+
+/* the Spaniard owns the dog */
+f3{h in HOUSE}: nationality[h,"Spaniard"] = pet[h,"dog"];
+
+/* coffee is drunk in the green house */
+f4{h in HOUSE}: drink[h,"coffee"] = color[h,"green"];
+
+/* the Ukrainian drinks tea */
+f5{h in HOUSE}: nationality[h,"Ukranian"] = drink[h,"tea"];
+
+/* the green house is immediately to the right of the ivory house */
+f6{h in HOUSE}:
+   color[h,"green"] = if h = 1 then 0 else color[h-1,"ivory"];
+
+/* the Old Gold smoker owns snails */
+f7{h in HOUSE}: smoke[h,"Old_Gold"] = pet[h,"snails"];
+
+/* Kools are smoked in the yellow house */
+f8{h in HOUSE}: smoke[h,"Kools"] = color[h,"yellow"];
+
+/* milk is drunk in the middle house */
+f9: drink[3,"milk"] = 1;
+
+/* the Norwegian lives in the first house */
+f10: nationality[1,"Norwegian"] = 1;
+
+/* the man who smokes Chesterfields lives in the house next to the man
+   with the fox */
+f11{h in HOUSE}:
+   (1 - smoke[h,"Chesterfield"]) +
+   (if h = 1 then 0 else pet[h-1,"fox"]) +
+   (if h = 5 then 0 else pet[h+1,"fox"]) >= 1;
+
+/* Kools are smoked in the house next to the house where the horse is
+   kept */
+f12{h in HOUSE}:
+   (1 - smoke[h,"Kools"]) +
+   (if h = 1 then 0 else pet[h-1,"horse"]) +
+   (if h = 5 then 0 else pet[h+1,"horse"]) >= 1;
+
+/* the Lucky Strike smoker drinks orange juice */
+f13{h in HOUSE}: smoke[h,"Lucky_Strike"] = drink[h,"orange_juice"];
+
+/* the Japanese smokes Parliaments */
+f14{h in HOUSE}: nationality[h,"Japanese"] = smoke[h,"Parliament"];
+
+/* the Norwegian lives next to the blue house */
+f15{h in HOUSE}:
+   (1 - nationality[h,"Norwegian"]) +
+   (if h = 1 then 0 else color[h-1,"blue"]) +
+   (if h = 5 then 0 else color[h+1,"blue"]) >= 1;
+
+solve;
+
+printf "\n";
+printf "HOUSE  COLOR   NATIONALITY  DRINK         SMOKE         PET\n";
+for {h in HOUSE}
+{  printf "%5d", h;
+   printf{c in COLOR: color[h,c]} "  %-6s", c;
+   printf{n in NATIONALITY: nationality[h,n]} "  %-11s", n;
+   printf{d in DRINK: drink[h,d]} "  %-12s", d;
+   printf{s in SMOKE: smoke[h,s]} "  %-12s", s;
+   printf{p in PET: pet[h,p]} "  %-6s", p;
+   printf "\n";
+}
+printf "\n";
+
+end;
Index: deps/glpk/install-sh
===================================================================
--- deps/glpk/install-sh	(revision 9)
+++ deps/glpk/install-sh	(revision 9)
@@ -0,0 +1,520 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2009-04-28.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""	$nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+	shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+	case $mode in
+	  *' '* | *'	'* | *'
+'*	  | *'*'* | *'?'* | *'['*)
+	    echo "$0: invalid mode: $mode" >&2
+	    exit 1;;
+	esac
+	shift;;
+
+    -o) chowncmd="$chownprog $2"
+	shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+	shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)	shift
+	break;;
+
+    -*)	echo "$0: invalid option: $1" >&2
+	exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call `install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  trap '(exit $?); exit' 1 2 13 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names starting with `-'.
+  case $src in
+    -*) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+
+    dst=$dst_arg
+    # Protect names starting with `-'.
+    case $dst in
+      -*) dst=./$dst;;
+    esac
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dst_arg: Is a directory" >&2
+	exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+	(dirname "$dst") 2>/dev/null ||
+	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	     X"$dst" : 'X\(//\)[^/]' \| \
+	     X"$dst" : 'X\(//\)$' \| \
+	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+	echo X"$dst" |
+	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)[^/].*/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\).*/{
+		   s//\1/
+		   q
+		 }
+		 s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+	# Create intermediate dirs using mode 755 as modified by the umask.
+	# This is like FreeBSD 'install' as of 1997-10-28.
+	umask=`umask`
+	case $stripcmd.$umask in
+	  # Optimize common cases.
+	  *[2367][2367]) mkdir_umask=$umask;;
+	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+	  *[0-7])
+	    mkdir_umask=`expr $umask + 22 \
+	      - $umask % 100 % 40 + $umask % 20 \
+	      - $umask % 10 % 4 + $umask % 2
+	    `;;
+	  *) mkdir_umask=$umask,go-w;;
+	esac
+
+	# With -d, create the new directory with the user-specified mode.
+	# Otherwise, rely on $mkdir_umask.
+	if test -n "$dir_arg"; then
+	  mkdir_mode=-m$mode
+	else
+	  mkdir_mode=
+	fi
+
+	posix_mkdir=false
+	case $umask in
+	  *[123567][0-7][0-7])
+	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
+	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+	    ;;
+	  *)
+	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+	    if (umask $mkdir_umask &&
+		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+	    then
+	      if test -z "$dir_arg" || {
+		   # Check for POSIX incompatibilities with -m.
+		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+		   # other-writeable bit of parent directory when it shouldn't.
+		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+		   case $ls_ld_tmpdir in
+		     d????-?r-*) different_mode=700;;
+		     d????-?--*) different_mode=755;;
+		     *) false;;
+		   esac &&
+		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+		   }
+		 }
+	      then posix_mkdir=:
+	      fi
+	      rmdir "$tmpdir/d" "$tmpdir"
+	    else
+	      # Remove any dirs left behind by ancient mkdir implementations.
+	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+	    fi
+	    trap '' 0;;
+	esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+	umask $mkdir_umask &&
+	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+	/*) prefix='/';;
+	-*) prefix='./';;
+	*)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+	test -z "$d" && continue
+
+	prefix=$prefix$d
+	if test -d "$prefix"; then
+	  prefixes=
+	else
+	  if $posix_mkdir; then
+	    (umask=$mkdir_umask &&
+	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+	    # Don't fail if two instances are running concurrently.
+	    test -d "$prefix" || exit 1
+	  else
+	    case $prefix in
+	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+	      *) qprefix=$prefix;;
+	    esac
+	    prefixes="$prefixes '$qprefix'"
+	  fi
+	fi
+	prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+	# Don't fail if two instances are running concurrently.
+	(umask $mkdir_umask &&
+	 eval "\$doit_exec \$mkdirprog $prefixes") ||
+	  test -d "$dstdir" || exit 1
+	obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+	# Now remove or move aside any old file at destination location.
+	# We try this two ways since rm can't unlink itself on some
+	# systems and the destination file might be busy for other
+	# reasons.  In this case, the final cleanup might fail but the new
+	# file should still install successfully.
+	{
+	  test ! -f "$dst" ||
+	  $doit $rmcmd -f "$dst" 2>/dev/null ||
+	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+	  } ||
+	  { echo "$0: cannot unlink or rename $dst" >&2
+	    (exit 1); exit 1
+	  }
+	} &&
+
+	# Now rename the file to the real destination.
+	$doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
Index: deps/glpk/ltmain.sh
===================================================================
--- deps/glpk/ltmain.sh	(revision 9)
+++ deps/glpk/ltmain.sh	(revision 9)
@@ -0,0 +1,9436 @@
+# Generated from ltmain.m4sh.
+
+# libtool (GNU libtool 1.3140 2009-12-30) 2.2.7a
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#         host-triplet:	$host
+#         shell:		$SHELL
+#         compiler:		$LTCC
+#         compiler flags:		$LTCFLAGS
+#         linker:		$LD (gnu? $with_gnu_ld)
+#         $progname:	(GNU libtool 1.3140 2009-12-30) 2.2.7a
+#         automake:	$automake_version
+#         autoconf:	$autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.2.7a
+TIMESTAMP=" 1.3140 2009-12-30"
+package_revision=1.3140
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+	  export $lt_var
+	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+	fi"
+done
+
+$lt_unset CDPATH
+
+
+
+
+
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${EGREP="/usr/bin/grep -E"}
+: ${FGREP="/usr/bin/grep -F"}
+: ${GREP="/usr/bin/grep"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SED="/usr/bin/sed"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+  # Extract subdirectory from the argument.
+  func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+  if test "X$func_dirname_result" = "X${1}"; then
+    func_dirname_result="${3}"
+  else
+    func_dirname_result="$func_dirname_result${2}"
+  fi
+  func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+}
+
+# Generated shell functions inserted here.
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+		s@/\./@/@g
+		t dotsl
+		s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=:
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname${mode+: }$mode: $*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+	IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+	func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+	my_arg=`$ECHO "$1" | $SED \
+	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+	    $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+  case "$1" in
+  [0-9]* | *[!a-zA-Z0-9_]*)
+    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+    ;;
+  * )
+    func_tr_sh_result=$1
+    ;;
+  esac
+}
+
+
+
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $SED -n '/(C)/!b go
+	:more
+	/\./!{
+	  N
+	  s/\n# //
+	  b more
+	}
+	:go
+	/^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+	s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $SED -n '/^# Usage:/,/^#  *-h/ {
+        s/^# //
+	s/^# *$//
+	s/\$progname/'$progname'/
+	p
+    }' < "$progpath"
+    echo
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+        s/^# //
+	s/^# *$//
+	s*\$progname*'$progname'*
+	s*\$host*'"$host"'*
+	s*\$SHELL*'"$SHELL"'*
+	s*\$LTCC*'"$LTCC"'*
+	s*\$LTCFLAGS*'"$LTCFLAGS"'*
+	s*\$LD*'"$LD"'*
+	s/\$with_gnu_ld/'"$with_gnu_ld"'/
+	s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/
+	s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/
+	p
+     }' < "$progpath"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    func_error "missing argument for $1"
+    exit_cmd=exit
+}
+
+exit_cmd=:
+
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+# $mode is unset
+nonopt=
+execute_dlfiles=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+opt_dry_run=false
+opt_duplicate_deps=false
+opt_silent=false
+opt_debug=:
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	taglist="$taglist $tagname"
+
+	# Evaluate the configuration.  Be careful to quote the path
+	# and the sed script, to avoid splitting on whitespace, but
+	# also don't use non-portable quotes within backquotes within
+	# quotes we have to do it in 2 steps:
+	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	eval "$extractedcf"
+      else
+	func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# Parse options once, thoroughly.  This comes as soon as possible in
+# the script to make things like `libtool --version' happen quickly.
+{
+
+  # Shorthand for --mode=foo, only valid as the first argument
+  case $1 in
+  clean|clea|cle|cl)
+    shift; set dummy --mode clean ${1+"$@"}; shift
+    ;;
+  compile|compil|compi|comp|com|co|c)
+    shift; set dummy --mode compile ${1+"$@"}; shift
+    ;;
+  execute|execut|execu|exec|exe|ex|e)
+    shift; set dummy --mode execute ${1+"$@"}; shift
+    ;;
+  finish|finis|fini|fin|fi|f)
+    shift; set dummy --mode finish ${1+"$@"}; shift
+    ;;
+  install|instal|insta|inst|ins|in|i)
+    shift; set dummy --mode install ${1+"$@"}; shift
+    ;;
+  link|lin|li|l)
+    shift; set dummy --mode link ${1+"$@"}; shift
+    ;;
+  uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+    shift; set dummy --mode uninstall ${1+"$@"}; shift
+    ;;
+  esac
+
+  # Parse non-mode specific arguments:
+  while test "$#" -gt 0; do
+    opt="$1"
+    shift
+
+    case $opt in
+      --config)		func_config					;;
+
+      --debug)		preserve_args="$preserve_args $opt"
+			func_echo "enabling shell trace mode"
+			opt_debug='set -x'
+			$opt_debug
+			;;
+
+      -dlopen)		test "$#" -eq 0 && func_missing_arg "$opt" && break
+			execute_dlfiles="$execute_dlfiles $1"
+			shift
+			;;
+
+      --dry-run | -n)	opt_dry_run=:					;;
+      --features)       func_features					;;
+      --finish)		mode="finish"					;;
+
+      --mode)		test "$#" -eq 0 && func_missing_arg "$opt" && break
+			case $1 in
+			  # Valid mode arguments:
+			  clean)	;;
+			  compile)	;;
+			  execute)	;;
+			  finish)	;;
+			  install)	;;
+			  link)		;;
+			  relink)	;;
+			  uninstall)	;;
+
+			  # Catch anything else as an error
+			  *) func_error "invalid argument for $opt"
+			     exit_cmd=exit
+			     break
+			     ;;
+		        esac
+
+			mode="$1"
+			shift
+			;;
+
+      --preserve-dup-deps)
+			opt_duplicate_deps=:				;;
+
+      --quiet|--silent)	preserve_args="$preserve_args $opt"
+			opt_silent=:
+			opt_verbose=false
+			;;
+
+      --no-quiet|--no-silent)
+			preserve_args="$preserve_args $opt"
+			opt_silent=false
+			;;
+
+      --verbose| -v)	preserve_args="$preserve_args $opt"
+			opt_silent=false
+			opt_verbose=:
+			;;
+
+      --no-verbose)	preserve_args="$preserve_args $opt"
+			opt_verbose=false
+			;;
+
+      --tag)		test "$#" -eq 0 && func_missing_arg "$opt" && break
+			preserve_args="$preserve_args $opt $1"
+			func_enable_tag "$1"	# tagname is set here
+			shift
+			;;
+
+      # Separate optargs to long options:
+      -dlopen=*|--mode=*|--tag=*)
+			func_opt_split "$opt"
+			set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"}
+			shift
+			;;
+
+      -\?|-h)		func_usage					;;
+      --help)		opt_help=:					;;
+      --help-all)	opt_help=': help-all'				;;
+      --version)	func_version					;;
+
+      -*)		func_fatal_help "unrecognized option \`$opt'"	;;
+
+      *)		nonopt="$opt"
+			break
+			;;
+    esac
+  done
+
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_duplicate_deps
+      ;;
+  esac
+
+  # Having warned about all mis-specified options, bail out if
+  # anything was wrong.
+  $exit_cmd $EXIT_FAILURE
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+$opt_help || {
+  # Sanity checks first:
+  func_check_version_match
+
+  if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+    func_fatal_configuration "not configured to build any kind of library"
+  fi
+
+  test -z "$mode" && func_fatal_error "error: you must specify a MODE."
+
+
+  # Darwin sucks
+  eval std_shrext=\"$shrext_cmds\"
+
+
+  # Only execute mode is allowed to have -dlopen flags.
+  if test -n "$execute_dlfiles" && test "$mode" != execute; then
+    func_error "unrecognized option \`-dlopen'"
+    $ECHO "$help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+
+  # Change the help message to a mode-specific one.
+  generic_help="$help"
+  help="Try \`$progname --help --mode=$mode' for more information."
+}
+
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case "$lalib_p_line" in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_ltwrapper_scriptname_result=""
+    if func_ltwrapper_executable_p "$1"; then
+	func_dirname_and_basename "$1" "" "."
+	func_stripname '' '.exe' "$func_basename_result"
+	func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+    fi
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+        func_quote_for_eval "$arg"
+	CC_quoted="$CC_quoted $func_quote_for_eval_result"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_quote_for_eval "$arg"
+	      CC_quoted="$CC_quoted $func_quote_for_eval_result"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with \`--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify \`-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          pie_flag="$pie_flag $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  later="$later $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+	  for arg in $args; do
+	    IFS="$save_ifs"
+	    func_quote_for_eval "$arg"
+	    lastarg="$lastarg $func_quote_for_eval_result"
+	  done
+	  IFS="$save_ifs"
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  base_compile="$base_compile $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_quote_for_eval "$lastarg"
+      base_compile="$base_compile $func_quote_for_eval_result"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      removelist="$removelist $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    removelist="$removelist $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    if test -n "$fix_srcfile_path"; then
+      eval srcfile=\"$fix_srcfile_path\"
+    fi
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	command="$command -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	command="$command -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      command="$command$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test "$mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to building PIC objects only
+  -prefer-non-pic   try to building non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $execute_dlfiles; do
+      test -f "$file" \
+	|| func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  dir="$dir/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+	;;
+
+      *)
+	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_quote_for_eval "$file"
+      args="$args $func_quote_for_eval_result"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libdirs="$nonopt"
+    admincmds=
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for dir
+      do
+	libdirs="$libdirs $dir"
+      done
+
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || admincmds="$admincmds
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    echo "----------------------------------------------------------------------"
+    echo "Libraries have been installed in:"
+    for libdir in $libdirs; do
+      $ECHO "   $libdir"
+    done
+    echo
+    echo "If you ever happen to want to link against installed libraries"
+    echo "in a given directory, LIBDIR, you must either use libtool, and"
+    echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+    echo "flag during linking and do at least one of the following:"
+    if test -n "$shlibpath_var"; then
+      echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      echo "     during execution"
+    fi
+    if test -n "$runpath_var"; then
+      echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+      echo "     during linking"
+    fi
+    if test -n "$hardcode_libdir_flag_spec"; then
+      libdir=LIBDIR
+      eval flag=\"$hardcode_libdir_flag_spec\"
+
+      $ECHO "   - use the \`$flag' linker flag"
+    fi
+    if test -n "$admincmds"; then
+      $ECHO "   - have your system administrator run these commands:$admincmds"
+    fi
+    if test -f /etc/ld.so.conf; then
+      echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+    fi
+    echo
+
+    echo "See any operating system documentation about shared libraries for"
+    case $host in
+      solaris2.[6789]|solaris2.1[0-9])
+        echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	echo "pages."
+	;;
+      *)
+        echo "more information, such as the ld(1) and ld.so(8) manual pages."
+        ;;
+    esac
+    echo "----------------------------------------------------------------------"
+    exit $EXIT_SUCCESS
+}
+
+test "$mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    install_prog="$install_prog$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	files="$files $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test "x$prev" = x-m && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      install_prog="$install_prog $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      install_shared_prog="$install_shared_prog $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	staticlibs="$staticlibs $file"
+	;;
+
+      *.la)
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) current_libdirs="$current_libdirs $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) future_libdirs="$future_libdirs $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir="$func_dirname_result"
+	dir="$dir$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking \`$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname="$1"
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme="$stripme"
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=""
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name="$func_basename_result"
+	instname="$dir/$name"i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "\`$lib' has not been installed in \`$libdir'"
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if test "$finalize" = yes; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file="$func_basename_result"
+	        outputname="$tmpdir/$file"
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_silent || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink \`$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file="$outputname"
+	      else
+	        func_warning "cannot relink \`$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms="${my_outputname}S.c"
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist="$output_objdir/${my_outputname}.nm"
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test "$dlself" = yes; then
+	  func_verbose "generating symbol list for \`$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_verbose "extracting global C symbols from \`$progfile'"
+	    $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols="$output_objdir/$outputname.exp"
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_basename "$dlprefile"
+	  name="$func_basename_result"
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=""
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname" ; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename="$func_basename_result"
+	          else
+	            # no lafile. user explicitly requested -dlpreopen <import library>.
+	            eval '$sharedlib_from_linklib "$dlprefile"'
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename" ; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+"
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc* )
+	    echo >> "$output_objdir/$my_dlsyms" "\
+/* DATA imports from DLLs on WIN32 con't be const, because
+   runtime relocations are performed -- see ld's documentation
+   on pseudo-relocs.  */"
+	    lt_dlsym_const= ;;
+	  *osf5*)
+	    echo >> "$output_objdir/$my_dlsyms" "\
+/* This system does not cope well with relocations in const data */"
+	    lt_dlsym_const= ;;
+	  *)
+	    lt_dlsym_const=const ;;
+	  esac
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+extern $lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+$lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    if test "X$my_pic_p" != Xno; then
+	      pic_flag_for_symtable=" $pic_flag"
+	    fi
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) symtab_cflags="$symtab_cflags $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei?-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      win32_nmres=`eval $NM -f posix -A $1 |
+	$SED -n -e '
+	    1,100{
+		/ I /{
+		    s,.*,import,
+		    p
+		    q
+		}
+	    }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $opt_debug
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $opt_debug
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    sed '/^Contents of section '"$1"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[ \t]*file format pe[i]\{,1\}-i386$/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remoaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    sed -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p
+      ' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive which possess that section. Heuristic: eliminate
+    # all those which have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    sed -e '/^\./d' -e '/^.\./d' | sed -n -e '1p'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $opt_debug
+  func_cygming_gnu_implib_tmp=`eval "\$NM \$1 | \$global_symbol_pipe | \$EGREP ' (_head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname)\\\$'"`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $opt_debug
+  func_cygming_ms_implib_tmp=`eval "\$NM \$1 | \$global_symbol_pipe | grep '_NULL_IMPORT_DESCRIPTOR'"`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $opt_debug
+  if func_cygming_gnu_implib_p "$1" ; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1" ; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=""
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`basename "$darwin_archive"`
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all exist in the "--lt-" namespace
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+}
+
+# Sets opts_contain_lt_result to \"yes\" if the
+# supplied arguments contain any elements in the
+# --lt-* namespace. Empty otherwise.
+opts_contain_lt_result=
+func_opts_contain_lt ()
+{
+  opts_contain_lt_result=
+  for lt_option
+  do
+    case \"\$lt_option\" in
+    --lt-*) opts_contain_lt_result=yes
+            break ;;
+    *) ;;
+    esac
+  done
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"(main) newargz[\$lt_dump_args_N]   : \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"(main) lt_argv_zero : \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"(main) lt_argv_zero : \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  func_opts_contain_lt \${1+\"\$@\"}
+  if test -n \"\$opts_contain_lt_result\"; then
+    # the following is adapted from _AC_INIT_PREPARE, except
+    # (1) we don't care about duplicates, and
+    # (2) we strip out --lt-*, not --no-create/--no-recursion/--silent
+    lt_wrapper_args=
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) continue ;;
+      *\\'*)
+        lt_wr_arg=\`\$ECHO \"X\$lt_wr_arg\" |
+          $SED -e \"s/^X//\" -e \"s/'/'\\\\\\\\\\\\\\\\''/g\"\`
+        ;;
+      esac
+      lt_wrapper_args=\"\$lt_wrapper_args '\$lt_wr_arg'\"
+    done
+    eval func_exec_program_core \$lt_wrapper_args
+  else
+    func_exec_program_core \${1+\"\$@\"}
+  fi
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	# fixup the dll searchpath if we need to.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+####################################
+# PATH CONVERSION HELPER FUNCTIONS #
+####################################
+
+# func_wine_to_win32_path ARG
+# Helper function used by path conversion functions
+# when $build is *nix, and $host is mingw, cygwin,
+# or some other win32 environment. Relies on a
+# correctly configured wine environment available,
+# with the winepath program in $build's $PATH.
+#
+# ARG is the $build path to be converted to win32 format.
+# result is available in $func_wine_to_win32_path_result
+# result is empty on error (or when arg is empty)
+func_wine_to_win32_path ()
+{
+  $opt_debug
+  lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+  func_wine_to_win32_path_result="$1"
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero
+    # error code, so we are forced to check the contents of
+    # stdout. On the other hand, if the command is not
+    # found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both
+    # error code of zero AND non-empty stdout, which explains
+    # the odd construction:
+    func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "${func_wine_to_win32_path_tmp}"; then
+      func_to_host_path_result=`$ECHO "$func_wine_to_win32_path_tmp" |
+        $SED -e "$lt_sed_naive_backslashify"`
+    else
+      func_wine_to_win32_path_result=
+    fi
+  fi
+}
+# end: func_wine_to_win32_path
+
+
+# func_wine_to_win32_pathlist ARG
+# Helper function used by path conversion functions
+# when $build is *nix, and $host is mingw, cygwin,
+# or some other win32 environment. Relies on a
+# correctly configured wine environment available,
+# with the winepath program in $build's $PATH.
+# Assumes ARG has no leading or trailing path separator
+# characters.
+#
+# ARG is pathlist to be converted from $build format to win32.
+# Result is available in $func_wine_to_win32_pathlist_result
+# Unconvertible paths in pathlist are skipped; if no paths
+# are convertible, result may be empty.
+func_wine_to_win32_pathlist ()
+{
+  $opt_debug
+  # unfortunately, winepath doesn't convert pathlists
+  func_wine_to_win32_pathlist_result=""
+  if test -n "$1"; then
+    func_wine_to_win32_pathlist_oldIFS=$IFS
+    IFS=:
+    for func_wine_to_win32_pathlist_f in $1; do
+      IFS=$func_wine_to_win32_pathlist_oldIFS
+      if test -n "$func_wine_to_win32_pathlist_f" ; then
+        func_wine_to_win32_path "$func_wine_to_win32_pathlist_f"
+        if test -n "$func_wine_to_win32_path_result" ; then
+          if test -z "$func_wine_to_win32_pathlist_result"; then
+            func_wine_to_win32_pathlist_result="$func_wine_to_win32_path_result"
+          else
+            func_append func_wine_to_win32_pathlist_result ";$func_wine_to_win32_path_result"
+          fi
+        fi
+      fi
+    done
+    IFS=$func_wine_to_win32_pathlist_oldIFS
+  fi
+}
+# end: func_wine_to_win32_pathlist
+
+
+# func_cygpath ARGS...
+# a wrapper around calling the cygpath program via
+# LT_CYGPATH, when $host is *nix and cygwin is
+# hosted via a wine environment (or, rarely, when
+# host is mingw -- that is, msys).
+#
+# Result is available in func_cygpath_result, which
+# may be empty on error. Can accomodate both paths
+# and pathlists (with appropriate options).
+#
+# ARGS are the typical arguments and options for
+# the cygpath program. Usually, the last argument
+# is the path or pathlist to be converted.
+#
+# The full *nix (or msys) path to the cygpath program must be
+# specified in the LT_CYGPATH environment variable. This
+# is because (a) the cygpath program shouldn't be in $PATH,
+# because it usually lives in cygwin's bin/ directory --
+# along with *cygwin* versions of sed, id, cp. If the *nix (or
+# msys) host environment had those programs in its $PATH, many
+# bad things could happen. (b) especially in cygwin-1.7, multiple
+# installations (with separate "mount tables" in
+# <CYGROOT-N>/etc/fstab) can coexist on the same Win32
+# instance. The cygpath.exe for cygwin installation #N in
+# <CYGROOT-N>/bin automatically deduces the appropriate
+# ../etc/fstab file. Therefore, it matters which cygpath.exe
+# is used. LT_CYGPATH may be replaced or supplemented by an
+# LT_INIT-activated configure option in the future.
+func_cygpath ()
+{
+  $opt_debug
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existant file: \`$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_msys_to_win32 ARG
+# Converts ARG from msys (unix-ish) format to
+# win32 format. Can accomodate both paths and pathlists.
+# Result is available in func_msys_to_win32_result.
+func_msys_to_win32 ()
+{
+  $opt_debug
+  lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+  # awkward: cmd appends spaces to result
+  func_msys_to_win32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_msys_to_win32
+
+
+# func_path_convert_check ARG1 ARG2
+# Verify that ARG1 (a path in $build format) was
+# converted to $host format in ARG2. Otherwise, emit
+# an error message, but continue (resetting
+# func_to_host_path_result to ARG1).
+func_path_convert_check ()
+{
+  $opt_debug
+  if test -z "$2" && test -n "$1" ; then
+    func_error "Could not determine host path corresponding to"
+    func_error "  \`$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_path_result="$1"
+  fi
+}
+# end func_path_convert_check
+
+
+# func_pathlist_convert_check FROM_PATHSEP TO_PATHSEP FROM_PATHLIST TO_PATHLIST
+# Verify that FROM_PATHLIST (a path in $build format) was converted
+# $host format in TO_PATHLIST. Otherwise, emit an error message, but
+# continue, resetting func_to_host_path_result to a simplistic
+# fallback value (see below).
+func_pathlist_convert_check ()
+{
+  $opt_debug
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path(s) corresponding to"
+    func_error "  \`$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback. If even this fallback fails, the fix is not to
+    # complicate the expression below, but for the user to provide,
+    # in that situation, whatever elements are missing from the
+    # environment so that the actual pathlist conversion functions
+    # work properly (for instance, a working wine installation
+    # with winepath so that path translation in the cross-to-mingw
+    # case works).
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_pathlist_result=`echo "$3" |\
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_pathlist_result="$3"
+    fi
+  fi
+}
+# end func_pathlist_convert_check
+
+
+# func_pathlist_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_pathlist_result by prepending REPL
+# if ORIG matches FRONTPAT and appending REPL if ORIG matches
+# BACKPAT.
+func_pathlist_front_back_pathsep ()
+{
+  $opt_debug
+  case "$4" in
+  $1 ) func_to_host_pathlist_result="$3$func_to_host_pathlist_result"
+    ;;
+  esac
+  case "$4" in
+  $2 ) func_append func_to_host_pathlist_result "$3"
+    ;;
+  esac
+}
+# end func_pathlist_front_back_pathsep
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `eval $to_host_path_cmd ARG'
+#
+# At present, the following path conversions are supported:
+#    $build          $host
+#    mingw (msys)    mingw  [e.g. native]
+#    cygwin          mingw
+#    *nix + wine     mingw
+#    mingw (msys)    cygwin [*] [**]
+#    *nix + wine     cygwin [**]
+# where wine is equipped with the `winepath' executable.
+# [*] available, but not officially supported. See comments with
+#     func_msys_to_cygwin_path_convert.
+# [**] requires environment variable $LT_CYGPATH. See comments
+#      with func_cygpath.
+# In each case, ARG is the path to be converted from $build
+# to $host format. the result will be available in
+# $func_to_host_path_result.
+
+
+# func_to_host_path ARG
+# converts the path ARG from $build format to $host
+# format.
+func_to_host_path ()
+{
+  $opt_debug
+  eval '$to_host_path_cmd "$1"'
+}
+# end func_to_host_path
+
+
+# func_noop_path_convert ARG
+# A no-op path conversion function for use when $build == $host.
+# or when there is no required (or known) conversion function
+# between $build and $host.
+func_noop_path_convert ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+}
+# end func_noop_path_convert
+
+
+# func_msys_to_mingw_path_convert ARG
+# A path conversion function for use with "native" mingw
+# builds -- that is, when $host is *mingw*, and $build
+# is *mingw* (which is to say, msys).  In this case, the
+# msys shell automatically converts paths for any non-msys
+# applications it launches, but that facility isn't available
+# from inside the cwrapper.
+#
+# ARG is the path to be converted; the result is available
+# in func_to_host_path_result.
+func_msys_to_mingw_path_convert ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    func_msys_to_win32 "$1"
+    func_to_host_path_result="$func_msys_to_win32_result"
+  fi
+  func_path_convert_check "$1" "$func_to_host_path_result"
+}
+# end func_msys_to_mingw_path_convert
+
+
+# func_cygwin_to_mingw_path_convert ARG
+# A path conversion function for use when $host is *mingw*
+# but $build is *cygwin*. In this case, the cygpath program
+# provided by the $build environment is sufficient for all
+# conversions.
+#
+# ARG is the path to be converted; the result is available
+# in func_to_host_path_result.
+func_cygwin_to_mingw_path_convert ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath
+    # in $PATH; no need to use LT_CYGPATH in this case.
+    func_to_host_path_result=`cygpath -m "$1"`
+  fi
+  func_path_convert_check "$1" "$func_to_host_path_result"
+}
+# end func_cygwin_to_mingw_path_convert
+
+
+# func_nix_to_mingw_path_convert ARG
+# A path conversion function for use when $host is *mingw*
+# but $build is some *nix variant. In this case, we assume
+# that a wine environment with a working winepath executable
+# is available in $build's $PATH.
+#
+# ARG is the path to be converted; the result is available
+# in func_to_host_path_result.
+func_nix_to_mingw_path_convert ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    func_wine_to_win32_path "$1"
+    func_to_host_path_result="$func_wine_to_win32_path_result"
+  fi
+  func_path_convert_check "$1" "$func_to_host_path_result"
+}
+# end func_nix_to_mingw_path_convert
+
+
+# func_msys_to_cygwin_path_convert ARG
+# A path conversion function for use when $host is *cygwin*
+# but $build is *mingw* (that is, msys). This implies running
+# a cross build from msys to cygwin -- but msys has notorious
+# problems executing cygwin apps, because of conflicts between
+# cygwin1.dll and msys-1.0.dll. However, we'll try it. First,
+# convert from msys to win32, then use func_cygpath to convert
+# from win32 to cygwin. Requires LT_CYGPATH.
+#
+# ARG is the path to be converted; the result is available
+# in func_to_host_path_result.
+func_msys_to_cygwin_path_convert ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    func_msys_to_win32 "$1"
+    func_cygpath -u "$func_msys_to_win32_result"
+    func_to_host_path_result="$func_cygpath_result"
+  fi
+  func_path_convert_check "$1" "$func_to_host_path_result"
+}
+# end func_msys_to_cygwin_path_convert
+
+# func_nix_to_cygwin_path_convert ARG
+# A path conversion function for use when $host is *cygwin*
+# but $build is some *nix variant. In this case, we assume
+# that a wine environment with a working winepath executable
+# is available in $build's $PATH, and that cygwin is installed
+# within that wine environment. Requires LT_CYGPATH (see
+# func_cygpath).
+#
+# ARG is the path to be converted; the result is available
+# in func_to_host_path_result.
+func_nix_to_cygwin_path_convert ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # convert from *nix to win32, then use cygpath to
+    # convert from win32 to cygwin.
+    func_wine_to_win32_path "$1"
+    func_cygpath -u "$func_wine_to_win32_path_result"
+    func_to_host_path_result="$func_cygpath_result"
+  fi
+  func_path_convert_check "$1" "$func_to_host_path_result"
+}
+# end func_nix_to_cygwin_path_convert
+
+
+#################################################
+# $build to $host PATHLIST CONVERSION FUNCTIONS #
+#################################################
+# invoked via `eval $to_host_pathlist_cmd ARG'
+#
+# At present, the following pathlist conversions are supported:
+#    $build          $host
+#    mingw (msys)    mingw  [e.g. native]
+#    cygwin          mingw
+#    *nix + wine     mingw
+#    mingw (msys)    cygwin [*] [**]
+#    *nix + wine     cygwin [**]
+# where wine is equipped with the `winepath' executable.
+# [*] available, but not officially supported. See comments with
+#     func_msys_to_cygwin_pathlist_convert.
+# [**] requires environment variable $LT_CYGPATH. See comments
+#      with func_cygpath.
+# In each case, ARG is the pathlist to be converted from
+# $build to $host format. the result will be available in
+# $func_to_host_pathlist_result.
+#
+# Path separators are also converted from $build format to
+# $host format. If ARG begins or ends with a path separator
+# character, it is preserved (but converted to $host format)
+# on output.
+
+
+# func_init_to_host_pathlist_cmd
+# Ensures that function "pointer" variable
+# $to_host_pathlist_cmd is set to the appropriate
+# value, based on the value of $to_host_path_cmd.
+#
+# ASSUMPTIONS: all such conversion functions are
+# named using the following convention:
+#   path conversion function    : xxxxxx_path_convert ()
+#   pathlist conversion function: xxxxxx_pathlist_convert ()
+# where, for any given $build/$host combination the 'xxxxxx'
+# value is the same.
+to_host_pathlist_cmd=
+func_init_to_host_pathlist_cmd ()
+{
+  $opt_debug
+  if test -z "$to_host_pathlist_cmd"; then
+    func_stripname '' '_path_convert' "$to_host_path_cmd"
+    to_host_pathlist_cmd="${func_stripname_result}_pathlist_convert"
+  fi
+}
+
+
+# func_to_host_pathlist ARG
+# converts the pathlist ARG from $build format to $host
+# format.
+func_to_host_pathlist ()
+{
+  $opt_debug
+  func_init_to_host_pathlist_cmd
+  eval '$to_host_pathlist_cmd "$1"'
+}
+# end func_to_host_pathlist
+
+
+# func_noop_pathlist_convert ARG
+# A no-op pathlist conversion function for use when $build == $host,
+# or when there is no required (or known) conversion function
+# between $build and $host.
+func_noop_pathlist_convert ()
+{
+  $opt_debug
+  func_to_host_pathlist_result="$1"
+}
+# end func_noop_pathlist_convert
+
+
+# func_msys_to_mingw_pathlist_convert ARG
+# A pathlist conversion function for use with "native" mingw
+# builds -- that is, when $host is *mingw*, and $build
+# is *mingw* (which is to say, msys).  In this case, the
+# msys shell automatically converts pathlists for any non-msys
+# applications it launches, but that facility isn't available
+# from inside the cwrapper.
+#
+# ARG is the pathlist to be converted; the result is available
+# in func_to_host_pathlist_result.
+func_msys_to_mingw_pathlist_convert ()
+{
+  $opt_debug
+  func_to_host_pathlist_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_pathlist_tmp1=$func_stripname_result
+    func_msys_to_win32 "$func_to_host_pathlist_tmp1"
+    func_to_host_pathlist_result="$func_msys_to_win32_result"
+    func_pathlist_convert_check ":" ";" \
+      "$func_to_host_pathlist_tmp1" "$func_to_host_pathlist_result"
+    func_pathlist_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_msys_to_mingw_pathlist_convert
+
+
+# func_cygwin_to_mingw_pathlist_convert ARG
+# A pathlist conversion function for use when $host is *mingw*
+# but $build is *cygwin*. In this case, the cygpath program
+# provided by the $build environment is sufficient for all
+# conversions.
+#
+# ARG is the pathlist to be converted; the result is available
+# in func_to_host_pathlist_result.
+func_cygwin_to_mingw_pathlist_convert ()
+{
+  $opt_debug
+  func_to_host_pathlist_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_pathlist_tmp1=$func_stripname_result
+    func_to_host_pathlist_result=`cygpath -m -p "$func_to_host_pathlist_tmp1"`
+    func_pathlist_convert_check ":" ";" \
+      "$func_to_host_pathlist_tmp1" "$func_to_host_pathlist_result"
+    func_pathlist_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_cygwin_to_mingw_pathlist_convert
+
+
+# func_nix_to_mingw_pathlist_convert ARG
+# A pathlist conversion function for use when $host is *mingw*
+# but $build is some *nix variant. In this case, we assume
+# that a wine environment with a working winepath executable
+# is available in $build's $PATH.
+#
+# ARG is the pathlist to be converted; the result is available
+# in func_to_host_pathlist_result.
+func_nix_to_mingw_pathlist_convert ()
+{
+  $opt_debug
+  func_to_host_pathlist_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_pathlist_tmp1=$func_stripname_result
+    func_wine_to_win32_pathlist "$func_to_host_pathlist_tmp1"
+    func_to_host_pathlist_result="$func_wine_to_win32_pathlist_result"
+    func_pathlist_convert_check ":" ";" \
+      "$func_to_host_pathlist_tmp1" "$func_to_host_pathlist_result"
+    func_pathlist_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_nix_to_mingw_pathlist_convert
+
+
+# func_msys_to_cygwin_pathlist_convert ARG
+# A pathlist conversion function for use when $host is *cygwin*
+# but $build is *mingw* (that is, msys). This implies running
+# a cross build from msys to cygwin -- but msys has notorious
+# problems executing cygwin apps, because of conflicts between
+# cygwin1.dll and msys-1.0.dll. However, we'll try it. First,
+# convert from msys to win32, then use func_cygpath to convert
+# from win32 to cygwin. Requires LT_CYGPATH.
+#
+# ARG is the pathlist to be converted; the result is available
+# in func_to_host_pathlist_result.
+func_msys_to_cygwin_pathlist_convert ()
+{
+  $opt_debug
+  func_to_host_pathlist_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_pathlist_tmp1=$func_stripname_result
+    func_msys_to_win32 "$func_to_host_pathlist_tmp1"
+    func_cygpath -u -p "$func_msys_to_win32_result"
+    func_to_host_pathlist_result="$func_cygpath_result"
+    func_pathlist_convert_check ":" ":" \
+      "$func_to_host_pathlist_tmp1" "$func_to_host_pathlist_result"
+    func_pathlist_front_back_pathsep ":*" "*:" ":" "$1"
+  fi
+}
+# end func_msys_to_cygwin_pathlist_convert
+
+
+# func_nix_to_cygwin_pathlist_convert ARG
+# A pathlist conversion function for use when $host is *cygwin*
+# but $build is some *nix variant. In this case, we assume
+# that a wine environment with a working winepath executable
+# is available in $build's $PATH, and that cygwin is installed
+# within that wine environment. Requires LT_CYGPATH (see
+# func_cygpath).
+#
+# ARG is the pathlist to be converted; the result is available
+# in func_to_host_pathlist_result.
+func_nix_to_cygwin_pathlist_convert ()
+{
+  $opt_debug
+  func_to_host_pathlist_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_pathlist_tmp1=$func_stripname_result
+    func_wine_to_win32_pathlist "$func_to_host_pathlist_tmp1"
+    func_cygpath -u -p "$func_wine_to_win32_pathlist_result"
+    func_to_host_pathlist_result="$func_cygpath_result"
+    func_pathlist_convert_check ":" ":" \
+      "$func_to_host_pathlist_tmp1" "$func_to_host_pathlist_result"
+    func_pathlist_front_back_pathsep ":*" "*:" ":" "$1"
+  fi
+}
+# end func_nix_to_cygwin_pathlist_convert
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+
+   Currently, it simply execs the wrapper *script* "$SHELL $output",
+   but could eventually absorb all of the scripts functionality and
+   exec $objdir/$outputname directly.
+*/
+EOF
+	    cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = NULL;
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *fmt, ...);
+void lt_fatal (const char *message, ...);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+
+EOF
+
+	    cat <<EOF
+const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_pathlist "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_pathlist_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_pathlist "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_pathlist_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test "$fast_install" = yes; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+#define LTWRAPPER_OPTION_PREFIX_LENGTH  5
+
+static const size_t opt_prefix_len         = LTWRAPPER_OPTION_PREFIX_LENGTH;
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const size_t dumpscript_opt_len  = LTWRAPPER_OPTION_PREFIX_LENGTH + 11;
+
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+static const size_t debug_opt_len       = LTWRAPPER_OPTION_PREFIX_LENGTH + 5;
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strncmp (argv[i], dumpscript_opt, dumpscript_opt_len) == 0)
+	{
+EOF
+	    case "$host" in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  lt_dump_script (stdout);
+	  return 0;
+	}
+      if (strncmp (argv[i], debug_opt, debug_opt_len) == 0)
+	{
+          lt_debug = 1;
+          continue;
+	}
+      if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal ("Unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+  /* first use of lt_debugprintf AFTER parsing options */
+  lt_debugprintf ("(main) argv[0]      : %s\n", argv[0]);
+  lt_debugprintf ("(main) program_name : %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal ("Couldn't find %s", argv[0]);
+  lt_debugprintf ("(main) found exe (before symlink chase) at : %s\n",
+		  tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf ("(main) found exe (after symlink chase) at : %s\n",
+		  actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf ("(main) libtool target name: %s\n",
+		  target_name);
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+
+  lt_debugprintf     ("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>"));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf ("(main) newargz[%d]   : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>"));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf ("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno);
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal ("Memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf ("(check_executable)  : %s\n",
+		  path ? (*path ? path : "EMPTY!") : "NULL!");
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf ("(make_executable)   : %s\n",
+		  path ? (*path ? path : "EMPTY!") : "NULL!");
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  lt_debugprintf ("(find_executable)   : %s\n",
+		  wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!");
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = q - p;
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal ("getcwd failed");
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal ("getcwd failed");
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf ("checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  char *errstr = strerror (errno);
+	  lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr);
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal ("Could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s: %s: ", program_name, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+  va_end (ap);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf ("(lt_setenv) setting '%s' to '%s'\n",
+                  (name ? name : "<NULL>"),
+                  (value ? value : "<NULL>"));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf ("(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  (name ? name : "<NULL>"),
+                  (value ? value : "<NULL>"));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf ("(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  (name ? name : "<NULL>"),
+                  (value ? value : "<NULL>"));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+              $SED -e 's/\([\\"]\)/\\\1/g' \
+	           -e 's/^/  fputs ("/' -e 's/$/\\n", f);/'
+
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_emit_exe_manifest
+# emit a Win32 UAC manifest for executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_exe_manifest ()
+{
+    cat <<EOF
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <assemblyIdentity version="1.0.0.0"
+EOF
+
+  case $host in
+  i?86-*-* )   echo '     processorArchitecture="x86"' ;;
+  ia64-*-* )   echo '     processorArchitecture="ia64"' ;;
+  x86_64-*-* ) echo '     processorArchitecture="amd64"' ;;
+  *)           echo '     processorArchitecture="*"' ;;
+  esac
+
+    cat <<EOF
+     name="$host_os.$PROGRAM.$outputname"
+     type="win32"/>
+
+  <!-- Identify the application security requirements. -->
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+</assembly>
+EOF
+}
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir="$arg"
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      dlfiles="$dlfiles $arg"
+	    else
+	      dlprefiles="$dlprefiles $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file \`$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) deplibs="$deplibs $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      moreargs="$moreargs $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none &&
+		   test "$non_pic_object" = none; then
+		  func_fatal_error "cannot find name of object for \`$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir="$func_dirname_result"
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      dlfiles="$dlfiles $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    dlprefiles="$dlprefiles $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir="$func_dirname_result"
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "\`$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file \`$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) rpath="$rpath $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) xrpath="$xrpath $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  weak_libs="$weak_libs $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname '-L' '' "$arg"
+	dir=$func_stripname_result
+	if test -z "$dir"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between \`-L' and \`$1'"
+	  else
+	    func_fatal_error "need path for \`-L' option"
+	  fi
+	fi
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "*) ;;
+	*)
+	  deplibs="$deplibs -L$dir"
+	  lib_search_path="$lib_search_path $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) dllsearchpath="$dllsearchpath:$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) dllsearchpath="$dllsearchpath:$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    deplibs="$deplibs System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	deplibs="$deplibs $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot)
+	compiler_flags="$compiler_flags $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+	compiler_flags="$compiler_flags $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "\`-no-install' is ignored for $host"
+	  func_warning "assuming \`-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) xrpath="$xrpath $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  arg="$arg $func_quote_for_eval_result"
+	  compiler_flags="$compiler_flags $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  arg="$arg $wl$func_quote_for_eval_result"
+	  compiler_flags="$compiler_flags $wl$func_quote_for_eval_result"
+	  linker_flags="$linker_flags $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+      # -r[0-9][0-9]* specifies the processor on the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+      # +DA*, +DD* enable 64-bit mode on the HP compiler
+      # -q* pass through compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* pass through architecture-specific
+      # compiler args for GCC
+      # -F/path gives path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+      # @file GCC response files
+      # -tp=* Portland pgcc target processor selection
+      # -{shared,static}-libgcc, -static-{libgfortran|libstdc++}: force GCC
+      # to link against specified runtime library.
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*| \
+      -shared-libgcc|-static-libgcc|-static-libgfortran|-static-libstdc++)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        compiler_flags="$compiler_flags $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      *.$objext)
+	# A standard object.
+	objs="$objs $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none &&
+	     test "$non_pic_object" = none; then
+	    func_fatal_error "cannot find name of object for \`$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir="$func_dirname_result"
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		dlfiles="$dlfiles $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      dlprefiles="$dlprefiles $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir="$func_dirname_result"
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "\`$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	deplibs="$deplibs $arg"
+	old_deplibs="$old_deplibs $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  dlfiles="$dlfiles $arg"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  dlprefiles="$dlprefiles $arg"
+	  prev=
+	else
+	  deplibs="$deplibs $arg"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_duplicate_deps ; then
+	case "$libs " in
+	*" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	esac
+      fi
+      libs="$libs $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+	  esac
+	  pre_post_deps="$pre_post_deps $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  case $lib in
+	  *.la)	func_source "$lib" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) deplibs="$deplibs $deplib" ;;
+	    esac
+	  done
+	done
+	libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    compiler_flags="$compiler_flags $deplib"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    func_warning "\`-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    func_dirname "$lib" "" "."
+		    ladir="$func_dirname_result"
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    newlib_search_path="$newlib_search_path $func_stripname_result"
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    newlib_search_path="$newlib_search_path $func_stripname_result"
+	    ;;
+	  *)
+	    func_warning "\`-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    func_stripname '-R' '' "$deplib"
+	    dir=$func_stripname_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) xrpath="$xrpath $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la) lib="$deplib" ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=no
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=yes
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=yes
+		;;
+	      esac
+	      if test "$valid_a_lib" != yes; then
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      else
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      newdlprefiles="$newdlprefiles $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      newdlfiles="$newdlfiles $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+	fi
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir="$func_dirname_result"
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+	  test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for \`$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    convenience="$convenience $ladir/$objdir/$old_library"
+	    old_convenience="$old_convenience $ladir/$objdir/$old_library"
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    func_fatal_error "\`$lib' is not a convenience library"
+	  fi
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    deplibs="$deplib $deplibs"
+	    if $opt_duplicate_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	for l in $old_library $library_names; do
+	  linklib="$l"
+	done
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for \`$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    dlprefiles="$dlprefiles $lib $dependency_libs"
+	  else
+	    newdlfiles="$newdlfiles $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname="$func_basename_result"
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library \`$lib' was moved."
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$libdir"
+	    absdir="$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    notinst_path="$notinst_path $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    notinst_path="$notinst_path $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir" && test "$linkmode" = prog; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	  fi
+	  case "$host" in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        newdlprefiles="$newdlprefiles $dir/$linklib"
+	      else
+	        newdlprefiles="$newdlprefiles $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        newdlprefiles="$newdlprefiles $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        newdlprefiles="$newdlprefiles $dir/$dlname"
+	      else
+	        newdlprefiles="$newdlprefiles $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  newlib_search_path="$newlib_search_path $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         newlib_search_path="$newlib_search_path $func_stripname_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_duplicate_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath:" in
+	      *"$absdir:"*) ;;
+	      *) temp_rpath="$temp_rpath$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc*)
+	      # No point in relinking DLLs because paths are not encoded
+	      notinst_deplibs="$notinst_deplibs $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test "$installed" = no; then
+	      notinst_deplibs="$notinst_deplibs $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=""
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule="$dlpremoduletest"
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	    echo
+	    if test "$linkmode" = prog; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname="$1"
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    func_basename "$soroot"
+	    soname="$func_basename_result"
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for \`$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we can not
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null ; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library" ; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add="$dir/$old_library"
+			fi
+		      elif test -n "$old_library"; then
+			add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes &&
+	         test "$hardcode_direct_absolute" = no; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$dir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes &&
+		 test "$hardcode_minus_L" != yes &&
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes &&
+	       test "$hardcode_direct_absolute" = no; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+		add="$inst_prefix_dir$libdir/$linklib"
+	      else
+		add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) xrpath="$xrpath $temp_xrpath";;
+		   esac;;
+	      *) temp_deplibs="$temp_deplibs $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  newlib_search_path="$newlib_search_path $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    if $opt_duplicate_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+	        func_dirname "$deplib" "" "."
+		dir="$func_dirname_result"
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of \`$dir'"
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl" ; then
+		      depdepl="$absdir/$objdir/$depdepl"
+		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+		      linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path="-L$absdir/$objdir"
+		  ;;
+		esac
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "\`$deplib' seems to be moved"
+
+		  path="-L$absdir"
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+	if test "$linkmode" = "prog"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) lib_search_path="$lib_search_path $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) tmp_libs="$tmp_libs $deplib" ;;
+	      esac
+	      ;;
+	    *) tmp_libs="$tmp_libs $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  tmp_libs="$tmp_libs $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      objs="$objs$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test "$module" = no && \
+	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  libobjs="$libobjs $objs"
+	fi
+      fi
+
+      test "$dlself" != no && \
+	func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+	func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	shift
+	IFS="$save_ifs"
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to \`-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$1"
+	  number_minor="$2"
+	  number_revision="$3"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  darwin|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|qnx|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$1"
+	  revision="$2"
+	  age="$3"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT \`$current' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION \`$revision' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE \`$age' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  verstring="$verstring:${current}.0"
+	  ;;
+
+	qnx)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    func_warning "undefined symbols not allowed in $host shared libraries"
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      libobjs="$libobjs $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       removelist="$removelist $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  temp_xrpath="$temp_xrpath -R$libdir"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) dlfiles="$dlfiles $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) dlprefiles="$dlprefiles $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    deplibs="$deplibs System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      deplibs="$deplibs -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    newdeplibs="$newdeplibs $i"
+		    i=""
+		    ;;
+		  esac
+		fi
+		if test -n "$i" ; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    newdeplibs="$newdeplibs $i"
+		  else
+		    droppeddeps=yes
+		    echo
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    echo "*** I have the capability to make that library automatically link in when"
+		    echo "*** you link to this library.  But I can only do this if you have a"
+		    echo "*** shared version of the library, which I believe you do not have"
+		    echo "*** because a test_compile did reveal that the linker did not use it for"
+		    echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		newdeplibs="$newdeplibs $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      newdeplibs="$newdeplibs $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      newdeplibs="$newdeplibs $i"
+		    else
+		      droppeddeps=yes
+		      echo
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      echo "*** I have the capability to make that library automatically link in when"
+		      echo "*** you link to this library.  But I can only do this if you have a"
+		      echo "*** shared version of the library, which you do not appear to have"
+		      echo "*** because a test_compile did reveal that the linker did not use this one"
+		      echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  echo
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  echo "*** make it link in!  You will probably need to install it or some"
+		  echo "*** library that it depends on before this library will be fully"
+		  echo "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		newdeplibs="$newdeplibs $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			newdeplibs="$newdeplibs $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      newdeplibs="$newdeplibs $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    new_libs="$new_libs -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) new_libs="$new_libs $deplib" ;;
+	  esac
+	  ;;
+	*) new_libs="$new_libs $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		dep_rpath="$dep_rpath $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) perm_rpath="$perm_rpath $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    if test -n "$hardcode_libdir_flag_spec_ld"; then
+	      eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+	    else
+	      eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+	    fi
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      rpath="$rpath$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname="$1"
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  linknames="$linknames $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols="$output_objdir/$libname.uexp"
+	  delfiles="$delfiles $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols="$export_symbols"
+	      export_symbols=
+	      always_export_symbols=yes
+	    fi
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $cmds; do
+	      IFS="$save_ifs"
+	      eval cmd=\"$cmd\"
+	      func_len " $cmd"
+	      len=$func_len_result
+	      if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols="$export_symbols"
+	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    tmp_deplibs="$tmp_deplibs $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test "$compiler_needs_object" = yes &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    generated="$generated $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    libobjs="$libobjs $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  linker_flags="$linker_flags $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+	    output=${output_objdir}/${output_la}.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      $ECHO "$obj" >> $output
+	    done
+	    echo ')' >> $output
+	    delfiles="$delfiles $output"
+	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+	    output=${output_objdir}/${output_la}.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test "$compiler_needs_object" = yes; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      $ECHO "$obj" >> $output
+	    done
+	    delfiles="$delfiles $output"
+	    output=$firstobj\"$file_list_spec$output\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-${k}.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test "X$objlist" = X ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test "$k" -eq 1 ; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-${k}.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	      fi
+	      delfiles="$delfiles $output"
+
+	    else
+	      output=
+	    fi
+
+	    if ${skipped_export-false}; then
+	      func_verbose "generating symbol list for \`$libname.la'"
+	      export_symbols="$output_objdir/$libname.exp"
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    fi
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS="$save_ifs"
+	      $opt_silent || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test "$mode" = relink; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS="$save_ifs"
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          if ${skipped_export-false}; then
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols="$export_symbols"
+	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  fi
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  generated="$generated $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  libobjs="$libobjs $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $opt_silent || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$mode" = relink; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  generated="$generated $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+	&& test "$dlopen_self" = unknown \
+	&& test "$dlopen_self_static" = unknown && \
+	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test "$tagname" = CXX ; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      compile_command="$compile_command ${wl}-bind_at_load"
+	      finalize_command="$finalize_command ${wl}-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    new_libs="$new_libs -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) new_libs="$new_libs $deplib" ;;
+	  esac
+	  ;;
+	*) new_libs="$new_libs $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      compile_command="$compile_command $compile_deplibs"
+      finalize_command="$finalize_command $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) perm_rpath="$perm_rpath $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) dllsearchpath="$dllsearchpath:$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) dllsearchpath="$dllsearchpath:$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.${objext}"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	func_warning "this platform does not like uninstalled shared libraries"
+	func_warning "\`$output' will be relinked during installation"
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
+	    cwrapper="$output_path/$output_name.exe"
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper $cwrapper.manifest; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host" ; then
+		# Create the UAC manifests first if necessary (but the
+		# manifest files must have executable permission regardless).
+		case $output_name in
+		  *instal*|*patch*|*setup*|*update*)
+		    func_emit_exe_manifest > $cwrapper.manifest
+		    func_emit_exe_manifest > $output_path/$objdir/$output_name.exe.manifest
+		    chmod +x $cwrapper.manifest
+		    chmod +x $output_path/$objdir/$output_name.exe.manifest
+		  ;;
+		esac
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save $symfileobj"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  if test "$preload" = yes && test -f "$symfileobj"; then
+	    oldobjs="$oldobjs $symfileobj"
+	  fi
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	generated="$generated $gentop"
+
+	func_extract_archives $gentop $addlibs
+	oldobjs="$oldobjs $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  generated="$generated $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  oldobjs="$oldobjs $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop="$output_objdir/${outputname}x"
+	  generated="$generated $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase="$func_basename_result"
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      oldobjs="$oldobjs $gentop/$newobj"
+	      ;;
+	    *) oldobjs="$oldobjs $obj" ;;
+	    esac
+	  done
+	fi
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		newdependency_libs="$newdependency_libs $libdir/$name"
+		;;
+	      *) newdependency_libs="$newdependency_libs $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		newdlfiles="$newdlfiles $libdir/$name"
+		;;
+	      *) newdlfiles="$newdlfiles $lib" ;;
+	      esac
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		newdlprefiles="$newdlprefiles $libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlfiles="$newdlfiles $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlprefiles="$newdlprefiles $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test "x$bindir" != x ;
+	      then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$mode" = link || test "$mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) RM="$RM $arg"; rmforce=yes ;;
+      -*) RM="$RM $arg" ;;
+      *) files="$files $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    origobjdir="$objdir"
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+	objdir="$origobjdir"
+      else
+	objdir="$dir/$origobjdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$mode" = uninstall && objdir="$dir"
+
+      # Remember objdir for removal later, being careful to avoid duplicates
+      if test "$mode" = clean; then
+	case " $rmdirs " in
+	  *" $objdir "*) ;;
+	  *) rmdirs="$rmdirs $objdir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    rmfiles="$rmfiles $objdir/$n"
+	  done
+	  test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+	  case "$mode" in
+	  clean)
+	    case "  $library_names " in
+	    # "  " in the beginning catches empty $dlname
+	    *" $dlname "*) ;;
+	    *) rmfiles="$rmfiles $objdir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" &&
+	     test "$pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" &&
+	     test "$non_pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    rmfiles="$rmfiles $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      rmfiles="$rmfiles $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+	    rmfiles="$rmfiles ${name}.manifest $objdir/${name}.manifest"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      rmfiles="$rmfiles $objdir/lt-$name $objdir/lt-${name}.manifest"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+    objdir="$origobjdir"
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$mode" = uninstall || test "$mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
Index: deps/glpk/m4/libtool.m4
===================================================================
--- deps/glpk/m4/libtool.m4	(revision 9)
+++ deps/glpk/m4/libtool.m4	(revision 9)
@@ -0,0 +1,7537 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 56 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_XSI_SHELLFNS
+
+  sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS="$save_LDFLAGS"
+    ])
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES
+# --------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX
+# -----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+sparc*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[AC_CHECK_TOOL(AR, ar, false)
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1])
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[123]]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+	 [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method == "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# ----------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+const struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_save_LIBS="$LIBS"
+	  lt_save_CFLAGS="$CFLAGS"
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS="$lt_save_LIBS"
+	  CFLAGS="$lt_save_CFLAGS"
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ F* | *Sun*Fortran*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+  ;;
+  cygwin* | mingw* | cegcc*)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+    _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+  ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  fi
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+      # FIXME: Should let the user specify the lib program.
+      _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+      _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    freebsd1*)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	m4_if($1, [], [
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  _LT_LINKER_OPTION([if $CC understands -b],
+	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+        save_LDFLAGS="$LDFLAGS"
+        LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+        AC_LINK_IFELSE(int foo(void) {},
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+        )
+        LDFLAGS="$save_LDFLAGS"
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	     ;;
+	   *)
+	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+	[$RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+	  _LT_TAGVAR(allow_undefined_flag, $1)=
+	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+	  then
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	  else
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  fi
+	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+	])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
+    [[If ld is used when linking, flag to hardcode $libdir into a binary
+    during linking.  This must work even if $libdir does not exist]])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [fix_srcfile_path], [1],
+    [Fix the shell variable $srcfile for the compiler])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	    if test "$with_gnu_ld" = yes; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    fi
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+        # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+        # as there is no search path for DLLs.
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+        _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+        _LT_TAGVAR(always_export_symbols, $1)=no
+        _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+        if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+          # If the export-symbols file already is a .def file (1st line
+          # is EXPORTS), use it as is; otherwise, prepend...
+          _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    cp $export_symbols $output_objdir/$soname.def;
+          else
+	    echo EXPORTS > $output_objdir/$soname.def;
+	    cat $export_symbols >> $output_objdir/$soname.def;
+          fi~
+          $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+        else
+          _LT_TAGVAR(ld_shlibs, $1)=no
+        fi
+        ;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd[[12]]*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+		$RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+	      '"$_LT_TAGVAR(old_archive_cmds, $1)"
+	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+	      '"$_LT_TAGVAR(reload_cmds, $1)"
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       else
+	 prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 case $p in
+	 -L* | -R*)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  CC=${F77-"f77"}
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  CC=${FC-"f95"}
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# --------------
+# If we don't have a new enough Autoconf to choose the best dlltool
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_XSI_SHELLFNS
+# ---------------------
+# Bourne and XSI compatible variants of some useful shell functions.
+m4_defun([_LT_PROG_XSI_SHELLFNS],
+[case $xsi_shell in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+  func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+  # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+  # positional parameters, so assign one to ordinary parameter first.
+  func_stripname_result=${3}
+  func_stripname_result=${func_stripname_result#"${1}"}
+  func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=${1%%=*}
+  func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  case ${1} in
+    *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+    *)    func_lo2o_result=${1} ;;
+  esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=$(( $[*] ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=${#1}
+}
+
+_LT_EOF
+    ;;
+  *) # Bourne compatible functions.
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  # Extract subdirectory from the argument.
+  func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+  if test "X$func_dirname_result" = "X${1}"; then
+    func_dirname_result="${3}"
+  else
+    func_dirname_result="$func_dirname_result${2}"
+  fi
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+}
+
+dnl func_dirname_and_basename
+dnl A portable version of this function is already defined in general.m4sh
+dnl so there is no need for it here.
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+  case ${2} in
+    .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[[^=]]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=`$ECHO "${1}" | $SED 's/\.[[^.]]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=`expr "$[@]"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$[1]+=\$[2]"
+}
+_LT_EOF
+    ;;
+  *)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$[1]=\$$[1]\$[2]"
+}
+
+_LT_EOF
+    ;;
+  esac
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which path conversion functions should be
+# used by func_to_host_path (and, implicitly, by
+# func_to_host_pathlist).  These are needed for certain
+# cross-compile configurations and "native" mingw (which
+# is actually an msys->mingw cross).
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build paths to $host format])
+AC_CACHE_VAL(lt_cv_to_host_path_cmd,
+[case $host in
+  *mingw* )
+    case $build in
+      *mingw* ) # actually msys
+        lt_cv_to_host_path_cmd=func_msys_to_mingw_path_convert
+        ;;
+      *cygwin* )
+        lt_cv_to_host_path_cmd=func_cygwin_to_mingw_path_convert
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_path_cmd=func_nix_to_mingw_path_convert
+        ;;
+    esac
+    ;;
+  *cygwin* )
+    case $build in
+      *mingw* ) # actually msys
+        lt_cv_to_host_path_cmd=func_msys_to_cygwin_path_convert
+        ;;
+      *cygwin* )
+        lt_cv_to_host_path_cmd=func_noop_path_convert
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_path_cmd=func_nix_to_cygwin_path_convert
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_path_cmd=func_noop_path_convert
+    ;;
+esac
+])
+to_host_path_cmd=$lt_cv_to_host_path_cmd
+AC_MSG_RESULT([$lt_cv_to_host_path_cmd])
+_LT_DECL([to_host_path_cmd], [lt_cv_to_host_path_cmd],
+         [0], [convert $build paths to $host format])dnl
+AC_SUBST([to_host_path_cmd])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
+
Index: deps/glpk/m4/ltoptions.m4
===================================================================
--- deps/glpk/m4/ltoptions.m4	(revision 9)
+++ deps/glpk/m4/ltoptions.m4	(revision 9)
@@ -0,0 +1,369 @@
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+  		   [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [pic_mode="$withval"],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
Index: deps/glpk/m4/ltsugar.m4
===================================================================
--- deps/glpk/m4/ltsugar.m4	(revision 9)
+++ deps/glpk/m4/ltsugar.m4	(revision 9)
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
Index: deps/glpk/m4/ltversion.m4
===================================================================
--- deps/glpk/m4/ltversion.m4	(revision 9)
+++ deps/glpk/m4/ltversion.m4	(revision 9)
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# Generated from ltversion.in.
+
+# serial 3140 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.2.7a])
+m4_define([LT_PACKAGE_REVISION], [1.3140])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.2.7a'
+macro_revision='1.3140'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
Index: deps/glpk/m4/lt~obsolete.m4
===================================================================
--- deps/glpk/m4/lt~obsolete.m4	(revision 9)
+++ deps/glpk/m4/lt~obsolete.m4	(revision 9)
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 4 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
Index: deps/glpk/missing
===================================================================
--- deps/glpk/missing	(revision 9)
+++ deps/glpk/missing	(revision 9)
@@ -0,0 +1,376 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  # Exit code 63 means version mismatch.  This often happens
+  # when the user try to use an ancient version of a tool on
+  # a file that requires a minimum version.  In this case we
+  # we should proceed has if the program had been absent, or
+  # if --run hadn't been passed.
+  if test $? = 63; then
+    run=:
+    msg="probably too old"
+  fi
+  ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  autom4te     touch the output file, or create a stub one
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+  s/^gnu-//; t
+  s/^gnu//; t
+  s/^g//; t'`
+
+# Now exit if we have it, but it failed.  Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).  This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+  lex*|yacc*)
+    # Not GNU programs, they don't have --version.
+    ;;
+
+  tar*)
+    if test -n "$run"; then
+       echo 1>&2 "ERROR: \`tar' requires --run"
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       exit 1
+    fi
+    ;;
+
+  *)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       # Could not run --version or --help.  This is probably someone
+       # running `$TOOL --version' or `$TOOL --help' to check whether
+       # $TOOL exists and not knowing $TOOL uses missing.
+       exit 1
+    fi
+    ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+  aclocal*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case $f in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  autom4te*)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo "#! /bin/sh"
+	echo "# Created by GNU Automake missing as a replacement of"
+	echo "#  $ $@"
+	echo "exit 0"
+	chmod +x $file
+	exit 1
+    fi
+    ;;
+
+  bison*|yacc*)
+    echo 1>&2 "\
+WARNING: \`$1' $msg.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if test $# -ne 1; then
+        eval LASTARG="\${$#}"
+	case $LASTARG in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if test ! -f y.tab.h; then
+	echo >y.tab.h
+    fi
+    if test ! -f y.tab.c; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex*|flex*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if test $# -ne 1; then
+        eval LASTARG="\${$#}"
+	case $LASTARG in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if test ! -f lex.yy.c; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+	 you modified a dependency of a manual page.  You may need the
+	 \`Help2man' package in order for those modifications to take
+	 effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo ".ab help2man is required to generate this page"
+	exit $?
+    fi
+    ;;
+
+  makeinfo*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    # The file to touch is that specified with -o ...
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -z "$file"; then
+      # ... or it is the one specified with @setfilename ...
+      infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '
+	/^@setfilename/{
+	  s/.* \([^ ]*\) *$/\1/
+	  p
+	  q
+	}' $infile`
+      # ... or it is derived from the source name (dir/f.texi becomes f.info)
+      test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+    fi
+    # If the file does not exist, the user really needs makeinfo;
+    # let's fail without touching anything.
+    test -f $file || exit 1
+    touch $file
+    ;;
+
+  tar*)
+    shift
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar "$@" && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar "$@" && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+	case $firstarg in
+	*o*)
+	    firstarg=`echo "$firstarg" | sed s/o//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+	case $firstarg in
+	*h*)
+	    firstarg=`echo "$firstarg" | sed s/h//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
Index: deps/glpk/src/Makefile.am
===================================================================
--- deps/glpk/src/Makefile.am	(revision 9)
+++ deps/glpk/src/Makefile.am	(revision 9)
@@ -0,0 +1,141 @@
+## Process this file with automake to produce Makefile.in ##
+
+include_HEADERS = glpk.h
+
+lib_LTLIBRARIES = libglpk.la
+
+libglpk_la_LDFLAGS = -version-info 32:0:32 \
+-export-symbols-regex '^(glp_|_glp_lpx_).*'
+
+libglpk_la_SOURCES = \
+glpapi01.c \
+glpapi02.c \
+glpapi03.c \
+glpapi04.c \
+glpapi05.c \
+glpapi06.c \
+glpapi07.c \
+glpapi08.c \
+glpapi09.c \
+glpapi10.c \
+glpapi11.c \
+glpapi12.c \
+glpapi13.c \
+glpapi14.c \
+glpapi15.c \
+glpapi16.c \
+glpapi17.c \
+glpapi18.c \
+glpapi19.c \
+glpapi20.c \
+glpapi21.c \
+glpavl.c \
+glpbfd.c \
+glpbfx.c \
+glpcpx.c \
+glpdmp.c \
+glpdmx.c \
+glpenv01.c \
+glpenv02.c \
+glpenv03.c \
+glpenv04.c \
+glpenv05.c \
+glpenv06.c \
+glpenv07.c \
+glpenv08.c \
+glpfhv.c \
+glpgmp.c \
+glphbm.c \
+glpini01.c \
+glpini02.c \
+glpios01.c \
+glpios02.c \
+glpios03.c \
+glpios04.c \
+glpios05.c \
+glpios06.c \
+glpios07.c \
+glpios08.c \
+glpios09.c \
+glpios10.c \
+glpios11.c \
+glpios12.c \
+glpipm.c \
+glplib01.c \
+glplib02.c \
+glplib03.c \
+glplpf.c \
+glplpx01.c \
+glplpx02.c \
+glplpx03.c \
+glpluf.c \
+glplux.c \
+glpmat.c \
+glpmpl01.c \
+glpmpl02.c \
+glpmpl03.c \
+glpmpl04.c \
+glpmpl05.c \
+glpmpl06.c \
+glpmps.c \
+glpnet01.c \
+glpnet02.c \
+glpnet03.c \
+glpnet04.c \
+glpnet05.c \
+glpnet06.c \
+glpnet07.c \
+glpnet08.c \
+glpnet09.c \
+glpnpp01.c \
+glpnpp02.c \
+glpnpp03.c \
+glpnpp04.c \
+glpnpp05.c \
+glpnpp06.c \
+glpqmd.c \
+glprgr.c \
+glprng01.c \
+glprng02.c \
+glpscf.c \
+glpscl.c \
+glpsdf.c \
+glpspm.c \
+glpspx01.c \
+glpspx02.c \
+glpsql.c \
+glpssx01.c \
+glpssx02.c \
+glptsp.c \
+amd/amd_1.c \
+amd/amd_2.c \
+amd/amd_aat.c \
+amd/amd_control.c \
+amd/amd_defaults.c \
+amd/amd_dump.c \
+amd/amd_info.c \
+amd/amd_order.c \
+amd/amd_post_tree.c \
+amd/amd_postorder.c \
+amd/amd_preprocess.c \
+amd/amd_valid.c \
+colamd/colamd.c \
+minisat/minisat.c \
+zlib/adler32.c \
+zlib/compress.c \
+zlib/crc32.c \
+zlib/deflate.c \
+zlib/gzclose.c \
+zlib/gzlib.c \
+zlib/gzread.c \
+zlib/gzwrite.c \
+zlib/infback.c \
+zlib/inffast.c \
+zlib/inflate.c \
+zlib/inftrees.c \
+zlib/trees.c \
+zlib/uncompr.c \
+zlib/zio.c \
+zlib/zutil.c
+
+## eof ##
Index: deps/glpk/src/Makefile.in
===================================================================
--- deps/glpk/src/Makefile.in	(revision 9)
+++ deps/glpk/src/Makefile.in	(revision 9)
@@ -0,0 +1,1040 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libglpk_la_LIBADD =
+am_libglpk_la_OBJECTS = glpapi01.lo glpapi02.lo glpapi03.lo \
+	glpapi04.lo glpapi05.lo glpapi06.lo glpapi07.lo glpapi08.lo \
+	glpapi09.lo glpapi10.lo glpapi11.lo glpapi12.lo glpapi13.lo \
+	glpapi14.lo glpapi15.lo glpapi16.lo glpapi17.lo glpapi18.lo \
+	glpapi19.lo glpapi20.lo glpapi21.lo glpavl.lo glpbfd.lo \
+	glpbfx.lo glpcpx.lo glpdmp.lo glpdmx.lo glpenv01.lo \
+	glpenv02.lo glpenv03.lo glpenv04.lo glpenv05.lo glpenv06.lo \
+	glpenv07.lo glpenv08.lo glpfhv.lo glpgmp.lo glphbm.lo \
+	glpini01.lo glpini02.lo glpios01.lo glpios02.lo glpios03.lo \
+	glpios04.lo glpios05.lo glpios06.lo glpios07.lo glpios08.lo \
+	glpios09.lo glpios10.lo glpios11.lo glpios12.lo glpipm.lo \
+	glplib01.lo glplib02.lo glplib03.lo glplpf.lo glplpx01.lo \
+	glplpx02.lo glplpx03.lo glpluf.lo glplux.lo glpmat.lo \
+	glpmpl01.lo glpmpl02.lo glpmpl03.lo glpmpl04.lo glpmpl05.lo \
+	glpmpl06.lo glpmps.lo glpnet01.lo glpnet02.lo glpnet03.lo \
+	glpnet04.lo glpnet05.lo glpnet06.lo glpnet07.lo glpnet08.lo \
+	glpnet09.lo glpnpp01.lo glpnpp02.lo glpnpp03.lo glpnpp04.lo \
+	glpnpp05.lo glpnpp06.lo glpqmd.lo glprgr.lo glprng01.lo \
+	glprng02.lo glpscf.lo glpscl.lo glpsdf.lo glpspm.lo \
+	glpspx01.lo glpspx02.lo glpsql.lo glpssx01.lo glpssx02.lo \
+	glptsp.lo amd_1.lo amd_2.lo amd_aat.lo amd_control.lo \
+	amd_defaults.lo amd_dump.lo amd_info.lo amd_order.lo \
+	amd_post_tree.lo amd_postorder.lo amd_preprocess.lo \
+	amd_valid.lo colamd.lo minisat.lo adler32.lo compress.lo \
+	crc32.lo deflate.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo \
+	infback.lo inffast.lo inflate.lo inftrees.lo trees.lo \
+	uncompr.lo zio.lo zutil.lo
+libglpk_la_OBJECTS = $(am_libglpk_la_OBJECTS)
+libglpk_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libglpk_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(libglpk_la_SOURCES)
+DIST_SOURCES = $(libglpk_la_SOURCES)
+HEADERS = $(include_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+to_host_path_cmd = @to_host_path_cmd@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+include_HEADERS = glpk.h
+lib_LTLIBRARIES = libglpk.la
+libglpk_la_LDFLAGS = -version-info 32:0:32 \
+-export-symbols-regex '^(glp_|_glp_lpx_).*'
+
+libglpk_la_SOURCES = \
+glpapi01.c \
+glpapi02.c \
+glpapi03.c \
+glpapi04.c \
+glpapi05.c \
+glpapi06.c \
+glpapi07.c \
+glpapi08.c \
+glpapi09.c \
+glpapi10.c \
+glpapi11.c \
+glpapi12.c \
+glpapi13.c \
+glpapi14.c \
+glpapi15.c \
+glpapi16.c \
+glpapi17.c \
+glpapi18.c \
+glpapi19.c \
+glpapi20.c \
+glpapi21.c \
+glpavl.c \
+glpbfd.c \
+glpbfx.c \
+glpcpx.c \
+glpdmp.c \
+glpdmx.c \
+glpenv01.c \
+glpenv02.c \
+glpenv03.c \
+glpenv04.c \
+glpenv05.c \
+glpenv06.c \
+glpenv07.c \
+glpenv08.c \
+glpfhv.c \
+glpgmp.c \
+glphbm.c \
+glpini01.c \
+glpini02.c \
+glpios01.c \
+glpios02.c \
+glpios03.c \
+glpios04.c \
+glpios05.c \
+glpios06.c \
+glpios07.c \
+glpios08.c \
+glpios09.c \
+glpios10.c \
+glpios11.c \
+glpios12.c \
+glpipm.c \
+glplib01.c \
+glplib02.c \
+glplib03.c \
+glplpf.c \
+glplpx01.c \
+glplpx02.c \
+glplpx03.c \
+glpluf.c \
+glplux.c \
+glpmat.c \
+glpmpl01.c \
+glpmpl02.c \
+glpmpl03.c \
+glpmpl04.c \
+glpmpl05.c \
+glpmpl06.c \
+glpmps.c \
+glpnet01.c \
+glpnet02.c \
+glpnet03.c \
+glpnet04.c \
+glpnet05.c \
+glpnet06.c \
+glpnet07.c \
+glpnet08.c \
+glpnet09.c \
+glpnpp01.c \
+glpnpp02.c \
+glpnpp03.c \
+glpnpp04.c \
+glpnpp05.c \
+glpnpp06.c \
+glpqmd.c \
+glprgr.c \
+glprng01.c \
+glprng02.c \
+glpscf.c \
+glpscl.c \
+glpsdf.c \
+glpspm.c \
+glpspx01.c \
+glpspx02.c \
+glpsql.c \
+glpssx01.c \
+glpssx02.c \
+glptsp.c \
+amd/amd_1.c \
+amd/amd_2.c \
+amd/amd_aat.c \
+amd/amd_control.c \
+amd/amd_defaults.c \
+amd/amd_dump.c \
+amd/amd_info.c \
+amd/amd_order.c \
+amd/amd_post_tree.c \
+amd/amd_postorder.c \
+amd/amd_preprocess.c \
+amd/amd_valid.c \
+colamd/colamd.c \
+minisat/minisat.c \
+zlib/adler32.c \
+zlib/compress.c \
+zlib/crc32.c \
+zlib/deflate.c \
+zlib/gzclose.c \
+zlib/gzlib.c \
+zlib/gzread.c \
+zlib/gzwrite.c \
+zlib/infback.c \
+zlib/inffast.c \
+zlib/inflate.c \
+zlib/inftrees.c \
+zlib/trees.c \
+zlib/uncompr.c \
+zlib/zio.c \
+zlib/zutil.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+libglpk.la: $(libglpk_la_OBJECTS) $(libglpk_la_DEPENDENCIES) 
+	$(libglpk_la_LINK) -rpath $(libdir) $(libglpk_la_OBJECTS) $(libglpk_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adler32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_aat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_control.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_defaults.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_dump.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_info.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_order.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_post_tree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_postorder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_preprocess.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amd_valid.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/colamd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compress.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/deflate.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi04.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi05.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi06.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi07.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi08.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi09.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi10.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi12.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi13.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi14.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi15.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi16.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi17.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi18.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi19.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi20.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpapi21.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpavl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpbfd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpbfx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpcpx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpdmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpdmx.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv04.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv05.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv06.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv07.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpenv08.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpfhv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpgmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glphbm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpini01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpini02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios04.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios05.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios06.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios07.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios08.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios09.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios10.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios11.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpios12.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpipm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplib01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplib02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplib03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplpf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplpx01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplpx02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplpx03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpluf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glplux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmpl01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmpl02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmpl03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmpl04.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmpl05.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmpl06.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpmps.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet04.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet05.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet06.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet07.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet08.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnet09.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnpp01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnpp02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnpp03.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnpp04.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnpp05.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpnpp06.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpqmd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glprgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glprng01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glprng02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpscf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpscl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpsdf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpspm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpspx01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpspx02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpsql.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpssx01.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glpssx02.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glptsp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gzclose.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gzlib.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gzread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gzwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/infback.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inffast.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inflate.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inftrees.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minisat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trees.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uncompr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zutil.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+amd_1.lo: amd/amd_1.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_1.lo -MD -MP -MF $(DEPDIR)/amd_1.Tpo -c -o amd_1.lo `test -f 'amd/amd_1.c' || echo '$(srcdir)/'`amd/amd_1.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_1.Tpo $(DEPDIR)/amd_1.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_1.c' object='amd_1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_1.lo `test -f 'amd/amd_1.c' || echo '$(srcdir)/'`amd/amd_1.c
+
+amd_2.lo: amd/amd_2.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_2.lo -MD -MP -MF $(DEPDIR)/amd_2.Tpo -c -o amd_2.lo `test -f 'amd/amd_2.c' || echo '$(srcdir)/'`amd/amd_2.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_2.Tpo $(DEPDIR)/amd_2.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_2.c' object='amd_2.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_2.lo `test -f 'amd/amd_2.c' || echo '$(srcdir)/'`amd/amd_2.c
+
+amd_aat.lo: amd/amd_aat.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_aat.lo -MD -MP -MF $(DEPDIR)/amd_aat.Tpo -c -o amd_aat.lo `test -f 'amd/amd_aat.c' || echo '$(srcdir)/'`amd/amd_aat.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_aat.Tpo $(DEPDIR)/amd_aat.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_aat.c' object='amd_aat.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_aat.lo `test -f 'amd/amd_aat.c' || echo '$(srcdir)/'`amd/amd_aat.c
+
+amd_control.lo: amd/amd_control.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_control.lo -MD -MP -MF $(DEPDIR)/amd_control.Tpo -c -o amd_control.lo `test -f 'amd/amd_control.c' || echo '$(srcdir)/'`amd/amd_control.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_control.Tpo $(DEPDIR)/amd_control.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_control.c' object='amd_control.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_control.lo `test -f 'amd/amd_control.c' || echo '$(srcdir)/'`amd/amd_control.c
+
+amd_defaults.lo: amd/amd_defaults.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_defaults.lo -MD -MP -MF $(DEPDIR)/amd_defaults.Tpo -c -o amd_defaults.lo `test -f 'amd/amd_defaults.c' || echo '$(srcdir)/'`amd/amd_defaults.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_defaults.Tpo $(DEPDIR)/amd_defaults.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_defaults.c' object='amd_defaults.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_defaults.lo `test -f 'amd/amd_defaults.c' || echo '$(srcdir)/'`amd/amd_defaults.c
+
+amd_dump.lo: amd/amd_dump.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_dump.lo -MD -MP -MF $(DEPDIR)/amd_dump.Tpo -c -o amd_dump.lo `test -f 'amd/amd_dump.c' || echo '$(srcdir)/'`amd/amd_dump.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_dump.Tpo $(DEPDIR)/amd_dump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_dump.c' object='amd_dump.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_dump.lo `test -f 'amd/amd_dump.c' || echo '$(srcdir)/'`amd/amd_dump.c
+
+amd_info.lo: amd/amd_info.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_info.lo -MD -MP -MF $(DEPDIR)/amd_info.Tpo -c -o amd_info.lo `test -f 'amd/amd_info.c' || echo '$(srcdir)/'`amd/amd_info.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_info.Tpo $(DEPDIR)/amd_info.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_info.c' object='amd_info.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_info.lo `test -f 'amd/amd_info.c' || echo '$(srcdir)/'`amd/amd_info.c
+
+amd_order.lo: amd/amd_order.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_order.lo -MD -MP -MF $(DEPDIR)/amd_order.Tpo -c -o amd_order.lo `test -f 'amd/amd_order.c' || echo '$(srcdir)/'`amd/amd_order.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_order.Tpo $(DEPDIR)/amd_order.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_order.c' object='amd_order.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_order.lo `test -f 'amd/amd_order.c' || echo '$(srcdir)/'`amd/amd_order.c
+
+amd_post_tree.lo: amd/amd_post_tree.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_post_tree.lo -MD -MP -MF $(DEPDIR)/amd_post_tree.Tpo -c -o amd_post_tree.lo `test -f 'amd/amd_post_tree.c' || echo '$(srcdir)/'`amd/amd_post_tree.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_post_tree.Tpo $(DEPDIR)/amd_post_tree.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_post_tree.c' object='amd_post_tree.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_post_tree.lo `test -f 'amd/amd_post_tree.c' || echo '$(srcdir)/'`amd/amd_post_tree.c
+
+amd_postorder.lo: amd/amd_postorder.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_postorder.lo -MD -MP -MF $(DEPDIR)/amd_postorder.Tpo -c -o amd_postorder.lo `test -f 'amd/amd_postorder.c' || echo '$(srcdir)/'`amd/amd_postorder.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_postorder.Tpo $(DEPDIR)/amd_postorder.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_postorder.c' object='amd_postorder.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_postorder.lo `test -f 'amd/amd_postorder.c' || echo '$(srcdir)/'`amd/amd_postorder.c
+
+amd_preprocess.lo: amd/amd_preprocess.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_preprocess.lo -MD -MP -MF $(DEPDIR)/amd_preprocess.Tpo -c -o amd_preprocess.lo `test -f 'amd/amd_preprocess.c' || echo '$(srcdir)/'`amd/amd_preprocess.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_preprocess.Tpo $(DEPDIR)/amd_preprocess.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_preprocess.c' object='amd_preprocess.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_preprocess.lo `test -f 'amd/amd_preprocess.c' || echo '$(srcdir)/'`amd/amd_preprocess.c
+
+amd_valid.lo: amd/amd_valid.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT amd_valid.lo -MD -MP -MF $(DEPDIR)/amd_valid.Tpo -c -o amd_valid.lo `test -f 'amd/amd_valid.c' || echo '$(srcdir)/'`amd/amd_valid.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/amd_valid.Tpo $(DEPDIR)/amd_valid.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='amd/amd_valid.c' object='amd_valid.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o amd_valid.lo `test -f 'amd/amd_valid.c' || echo '$(srcdir)/'`amd/amd_valid.c
+
+colamd.lo: colamd/colamd.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT colamd.lo -MD -MP -MF $(DEPDIR)/colamd.Tpo -c -o colamd.lo `test -f 'colamd/colamd.c' || echo '$(srcdir)/'`colamd/colamd.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/colamd.Tpo $(DEPDIR)/colamd.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='colamd/colamd.c' object='colamd.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o colamd.lo `test -f 'colamd/colamd.c' || echo '$(srcdir)/'`colamd/colamd.c
+
+minisat.lo: minisat/minisat.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minisat.lo -MD -MP -MF $(DEPDIR)/minisat.Tpo -c -o minisat.lo `test -f 'minisat/minisat.c' || echo '$(srcdir)/'`minisat/minisat.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/minisat.Tpo $(DEPDIR)/minisat.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='minisat/minisat.c' object='minisat.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minisat.lo `test -f 'minisat/minisat.c' || echo '$(srcdir)/'`minisat/minisat.c
+
+adler32.lo: zlib/adler32.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT adler32.lo -MD -MP -MF $(DEPDIR)/adler32.Tpo -c -o adler32.lo `test -f 'zlib/adler32.c' || echo '$(srcdir)/'`zlib/adler32.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/adler32.Tpo $(DEPDIR)/adler32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/adler32.c' object='adler32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o adler32.lo `test -f 'zlib/adler32.c' || echo '$(srcdir)/'`zlib/adler32.c
+
+compress.lo: zlib/compress.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT compress.lo -MD -MP -MF $(DEPDIR)/compress.Tpo -c -o compress.lo `test -f 'zlib/compress.c' || echo '$(srcdir)/'`zlib/compress.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/compress.Tpo $(DEPDIR)/compress.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/compress.c' object='compress.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o compress.lo `test -f 'zlib/compress.c' || echo '$(srcdir)/'`zlib/compress.c
+
+crc32.lo: zlib/crc32.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crc32.lo -MD -MP -MF $(DEPDIR)/crc32.Tpo -c -o crc32.lo `test -f 'zlib/crc32.c' || echo '$(srcdir)/'`zlib/crc32.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/crc32.Tpo $(DEPDIR)/crc32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/crc32.c' object='crc32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o crc32.lo `test -f 'zlib/crc32.c' || echo '$(srcdir)/'`zlib/crc32.c
+
+deflate.lo: zlib/deflate.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT deflate.lo -MD -MP -MF $(DEPDIR)/deflate.Tpo -c -o deflate.lo `test -f 'zlib/deflate.c' || echo '$(srcdir)/'`zlib/deflate.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/deflate.Tpo $(DEPDIR)/deflate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/deflate.c' object='deflate.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o deflate.lo `test -f 'zlib/deflate.c' || echo '$(srcdir)/'`zlib/deflate.c
+
+gzclose.lo: zlib/gzclose.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gzclose.lo -MD -MP -MF $(DEPDIR)/gzclose.Tpo -c -o gzclose.lo `test -f 'zlib/gzclose.c' || echo '$(srcdir)/'`zlib/gzclose.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/gzclose.Tpo $(DEPDIR)/gzclose.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/gzclose.c' object='gzclose.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gzclose.lo `test -f 'zlib/gzclose.c' || echo '$(srcdir)/'`zlib/gzclose.c
+
+gzlib.lo: zlib/gzlib.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gzlib.lo -MD -MP -MF $(DEPDIR)/gzlib.Tpo -c -o gzlib.lo `test -f 'zlib/gzlib.c' || echo '$(srcdir)/'`zlib/gzlib.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/gzlib.Tpo $(DEPDIR)/gzlib.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/gzlib.c' object='gzlib.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gzlib.lo `test -f 'zlib/gzlib.c' || echo '$(srcdir)/'`zlib/gzlib.c
+
+gzread.lo: zlib/gzread.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gzread.lo -MD -MP -MF $(DEPDIR)/gzread.Tpo -c -o gzread.lo `test -f 'zlib/gzread.c' || echo '$(srcdir)/'`zlib/gzread.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/gzread.Tpo $(DEPDIR)/gzread.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/gzread.c' object='gzread.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gzread.lo `test -f 'zlib/gzread.c' || echo '$(srcdir)/'`zlib/gzread.c
+
+gzwrite.lo: zlib/gzwrite.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gzwrite.lo -MD -MP -MF $(DEPDIR)/gzwrite.Tpo -c -o gzwrite.lo `test -f 'zlib/gzwrite.c' || echo '$(srcdir)/'`zlib/gzwrite.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/gzwrite.Tpo $(DEPDIR)/gzwrite.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/gzwrite.c' object='gzwrite.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gzwrite.lo `test -f 'zlib/gzwrite.c' || echo '$(srcdir)/'`zlib/gzwrite.c
+
+infback.lo: zlib/infback.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT infback.lo -MD -MP -MF $(DEPDIR)/infback.Tpo -c -o infback.lo `test -f 'zlib/infback.c' || echo '$(srcdir)/'`zlib/infback.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/infback.Tpo $(DEPDIR)/infback.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/infback.c' object='infback.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o infback.lo `test -f 'zlib/infback.c' || echo '$(srcdir)/'`zlib/infback.c
+
+inffast.lo: zlib/inffast.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inffast.lo -MD -MP -MF $(DEPDIR)/inffast.Tpo -c -o inffast.lo `test -f 'zlib/inffast.c' || echo '$(srcdir)/'`zlib/inffast.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/inffast.Tpo $(DEPDIR)/inffast.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/inffast.c' object='inffast.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inffast.lo `test -f 'zlib/inffast.c' || echo '$(srcdir)/'`zlib/inffast.c
+
+inflate.lo: zlib/inflate.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inflate.lo -MD -MP -MF $(DEPDIR)/inflate.Tpo -c -o inflate.lo `test -f 'zlib/inflate.c' || echo '$(srcdir)/'`zlib/inflate.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/inflate.Tpo $(DEPDIR)/inflate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/inflate.c' object='inflate.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inflate.lo `test -f 'zlib/inflate.c' || echo '$(srcdir)/'`zlib/inflate.c
+
+inftrees.lo: zlib/inftrees.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inftrees.lo -MD -MP -MF $(DEPDIR)/inftrees.Tpo -c -o inftrees.lo `test -f 'zlib/inftrees.c' || echo '$(srcdir)/'`zlib/inftrees.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/inftrees.Tpo $(DEPDIR)/inftrees.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/inftrees.c' object='inftrees.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inftrees.lo `test -f 'zlib/inftrees.c' || echo '$(srcdir)/'`zlib/inftrees.c
+
+trees.lo: zlib/trees.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trees.lo -MD -MP -MF $(DEPDIR)/trees.Tpo -c -o trees.lo `test -f 'zlib/trees.c' || echo '$(srcdir)/'`zlib/trees.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/trees.Tpo $(DEPDIR)/trees.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/trees.c' object='trees.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trees.lo `test -f 'zlib/trees.c' || echo '$(srcdir)/'`zlib/trees.c
+
+uncompr.lo: zlib/uncompr.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT uncompr.lo -MD -MP -MF $(DEPDIR)/uncompr.Tpo -c -o uncompr.lo `test -f 'zlib/uncompr.c' || echo '$(srcdir)/'`zlib/uncompr.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/uncompr.Tpo $(DEPDIR)/uncompr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/uncompr.c' object='uncompr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o uncompr.lo `test -f 'zlib/uncompr.c' || echo '$(srcdir)/'`zlib/uncompr.c
+
+zio.lo: zlib/zio.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zio.lo -MD -MP -MF $(DEPDIR)/zio.Tpo -c -o zio.lo `test -f 'zlib/zio.c' || echo '$(srcdir)/'`zlib/zio.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/zio.Tpo $(DEPDIR)/zio.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/zio.c' object='zio.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zio.lo `test -f 'zlib/zio.c' || echo '$(srcdir)/'`zlib/zio.c
+
+zutil.lo: zlib/zutil.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zutil.lo -MD -MP -MF $(DEPDIR)/zutil.Tpo -c -o zutil.lo `test -f 'zlib/zutil.c' || echo '$(srcdir)/'`zlib/zutil.c
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/zutil.Tpo $(DEPDIR)/zutil.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='zlib/zutil.c' object='zutil.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zutil.lo `test -f 'zlib/zutil.c' || echo '$(srcdir)/'`zlib/zutil.c
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(includedir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libLTLIBRARIES clean-libtool ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-includeHEADERS install-info \
+	install-info-am install-libLTLIBRARIES install-man install-pdf \
+	install-pdf-am install-ps install-ps-am install-strip \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-includeHEADERS \
+	uninstall-libLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: deps/glpk/src/amd/COPYING
===================================================================
--- deps/glpk/src/amd/COPYING	(revision 9)
+++ deps/glpk/src/amd/COPYING	(revision 9)
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
Index: deps/glpk/src/amd/README
===================================================================
--- deps/glpk/src/amd/README	(revision 9)
+++ deps/glpk/src/amd/README	(revision 9)
@@ -0,0 +1,58 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+      are used with GLPK.
+
+      The original code was modified according to GLPK requirements by
+      Andrew Makhorin <mao@gnu.org>.
+************************************************************************
+AMD Version 2.2, Copyright (C) 2007 by Timothy A. Davis,
+Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+Description:
+
+   AMD is a set of routines for pre-ordering sparse matrices prior to
+   Cholesky or LU factorization, using the approximate minimum degree
+   ordering algorithm.  Written in ANSI/ISO C with a MATLAB interface,
+   and in Fortran 77.
+
+Authors:
+
+   Timothy A. Davis (davis at cise.ufl.edu), University of Florida.
+   Patrick R. Amestoy, ENSEEIHT, Toulouse, France.
+   Iain S. Duff, Rutherford Appleton Laboratory, UK.
+
+AMD License:
+
+   Your use or distribution of AMD or any modified version of AMD
+   implies that you agree to this License.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+   USA.
+
+   Permission is hereby granted to use or copy this program under the
+   terms of the GNU LGPL, provided that the Copyright, this License,
+   and the Availability of the original version is retained on all
+   copies.  User documentation of any code that uses this code or any
+   modified version of this code must cite the Copyright, this License,
+   the Availability note, and "Used by permission."  Permission to
+   modify the code and to distribute modified code is granted, provided
+   the Copyright, this License, and the Availability note are retained,
+   and a notice that the code was modified is included.
+
+   AMD is available under alternate licences; contact T. Davis for
+   details.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/amd
Index: deps/glpk/src/amd/amd.h
===================================================================
--- deps/glpk/src/amd/amd.h	(revision 9)
+++ deps/glpk/src/amd/amd.h	(revision 9)
@@ -0,0 +1,67 @@
+/* amd.h */
+
+/* Written by Andrew Makhorin <mao@gnu.org>. */
+
+#ifndef GLPAMD_H
+#define GLPAMD_H
+
+#define AMD_DATE "May 31, 2007"
+#define AMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
+#define AMD_MAIN_VERSION 2
+#define AMD_SUB_VERSION 2
+#define AMD_SUBSUB_VERSION 0
+#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION, AMD_SUB_VERSION)
+
+#define AMD_CONTROL 5
+#define AMD_INFO 20
+
+#define AMD_DENSE 0
+#define AMD_AGGRESSIVE 1
+
+#define AMD_DEFAULT_DENSE 10.0
+#define AMD_DEFAULT_AGGRESSIVE 1
+
+#define AMD_STATUS         0
+#define AMD_N              1
+#define AMD_NZ             2
+#define AMD_SYMMETRY       3
+#define AMD_NZDIAG         4
+#define AMD_NZ_A_PLUS_AT   5
+#define AMD_NDENSE         6
+#define AMD_MEMORY         7
+#define AMD_NCMPA          8
+#define AMD_LNZ            9
+#define AMD_NDIV           10
+#define AMD_NMULTSUBS_LDL  11
+#define AMD_NMULTSUBS_LU   12
+#define AMD_DMAX           13
+
+#define AMD_OK             0
+#define AMD_OUT_OF_MEMORY  (-1)
+#define AMD_INVALID        (-2)
+#define AMD_OK_BUT_JUMBLED 1
+
+#define amd_order _glp_amd_order
+int amd_order(int n, const int Ap[], const int Ai[], int P[],
+      double Control[], double Info[]);
+
+#define amd_2 _glp_amd_2
+void amd_2(int n, int Pe[], int Iw[], int Len[], int iwlen, int pfree,
+      int Nv[], int Next[], int Last[], int Head[], int Elen[],
+      int Degree[], int W[], double Control[], double Info[]);
+
+#define amd_valid _glp_amd_valid
+int amd_valid(int n_row, int n_col, const int Ap[], const int Ai[]);
+
+#define amd_defaults _glp_amd_defaults
+void amd_defaults(double Control[]);
+
+#define amd_control _glp_amd_control
+void amd_control(double Control[]);
+
+#define amd_info _glp_amd_info
+void amd_info(double Info[]);
+
+#endif
+
+/* eof */
Index: deps/glpk/src/amd/amd_1.c
===================================================================
--- deps/glpk/src/amd/amd_1.c	(revision 9)
+++ deps/glpk/src/amd/amd_1.c	(revision 9)
@@ -0,0 +1,181 @@
+/* ========================================================================= */
+/* === AMD_1 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
+ *
+ * The n-by-n sparse matrix A can be unsymmetric.  It is stored in MATLAB-style
+ * compressed-column form, with sorted row indices in each column, and no
+ * duplicate entries.  Diagonal entries may be present, but they are ignored.
+ * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A.  The
+ * size of the matrix, n, must be greater than or equal to zero.
+ *
+ * This routine must be preceded by a call to AMD_aat, which computes the
+ * number of entries in each row/column in A+A', excluding the diagonal.
+ * Len [j], on input, is the number of entries in row/column j of A+A'.  This
+ * routine constructs the matrix A+A' and then calls AMD_2.  No error checking
+ * is performed (this was done in AMD_valid).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_1
+(
+    Int n,              /* n > 0 */
+    const Int Ap [ ],   /* input of size n+1, not modified */
+    const Int Ai [ ],   /* input of size nz = Ap [n], not modified */
+    Int P [ ],          /* size n output permutation */
+    Int Pinv [ ],       /* size n output inverse permutation */
+    Int Len [ ],        /* size n input, undefined on output */
+    Int slen,           /* slen >= sum (Len [0..n-1]) + 7n,
+                         * ideally slen = 1.2 * sum (Len) + 8n */
+    Int S [ ],          /* size slen workspace */
+    double Control [ ], /* input array of size AMD_CONTROL */
+    double Info [ ]     /* output array of size AMD_INFO */
+)
+{
+    Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
+        *Elen, *Degree, *s, *W, *Sp, *Tp ;
+
+    /* --------------------------------------------------------------------- */
+    /* construct the matrix for AMD_2 */
+    /* --------------------------------------------------------------------- */
+
+    ASSERT (n > 0) ;
+
+    iwlen = slen - 6*n ;
+    s = S ;
+    Pe = s ;        s += n ;
+    Nv = s ;        s += n ;
+    Head = s ;      s += n ;
+    Elen = s ;      s += n ;
+    Degree = s ;    s += n ;
+    W = s ;         s += n ;
+    Iw = s ;        s += iwlen ;
+
+    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+
+    /* construct the pointers for A+A' */
+    Sp = Nv ;                   /* use Nv and W as workspace for Sp and Tp [ */
+    Tp = W ;
+    pfree = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+        Pe [j] = pfree ;
+        Sp [j] = pfree ;
+        pfree += Len [j] ;
+    }
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is strictly required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be very slow.  For better performance, at
+     * least size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+
+#ifndef NDEBUG
+    for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
+#endif
+
+    for (k = 0 ; k < n ; k++)
+    {
+        AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k))  ;
+        p1 = Ap [k] ;
+        p2 = Ap [k+1] ;
+
+        /* construct A+A' */
+        for (p = p1 ; p < p2 ; )
+        {
+            /* scan the upper triangular part of A */
+            j = Ai [p] ;
+            ASSERT (j >= 0 && j < n) ;
+            if (j < k)
+            {
+                /* entry A (j,k) in the strictly upper triangular part */
+                ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+                ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
+                Iw [Sp [j]++] = k ;
+                Iw [Sp [k]++] = j ;
+                p++ ;
+            }
+            else if (j == k)
+            {
+                /* skip the diagonal */
+                p++ ;
+                break ;
+            }
+            else /* j > k */
+            {
+                /* first entry below the diagonal */
+                break ;
+            }
+            /* scan lower triangular part of A, in column j until reaching
+             * row k.  Start where last scan left off. */
+            ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+            pj2 = Ap [j+1] ;
+            for (pj = Tp [j] ; pj < pj2 ; )
+            {
+                i = Ai [pj] ;
+                ASSERT (i >= 0 && i < n) ;
+                if (i < k)
+                {
+                    /* A (i,j) is only in the lower part, not in upper */
+                    ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+                    ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+                    Iw [Sp [i]++] = j ;
+                    Iw [Sp [j]++] = i ;
+                    pj++ ;
+                }
+                else if (i == k)
+                {
+                    /* entry A (k,j) in lower part and A (j,k) in upper */
+                    pj++ ;
+                    break ;
+                }
+                else /* i > k */
+                {
+                    /* consider this entry later, when k advances to i */
+                    break ;
+                }
+            }
+            Tp [j] = pj ;
+        }
+        Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+        for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+        {
+            i = Ai [pj] ;
+            ASSERT (i >= 0 && i < n) ;
+            /* A (i,j) is only in the lower part, not in upper */
+            ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+            ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+            Iw [Sp [i]++] = j ;
+            Iw [Sp [j]++] = i ;
+        }
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
+    ASSERT (Sp [n-1] == pfree) ;
+#endif
+
+    /* Tp and Sp no longer needed ] */
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
+        Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
+}
Index: deps/glpk/src/amd/amd_2.c
===================================================================
--- deps/glpk/src/amd/amd_2.c	(revision 9)
+++ deps/glpk/src/amd/amd_2.c	(revision 9)
@@ -0,0 +1,1842 @@
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_2:  performs the AMD ordering on a symmetric sparse matrix A, followed
+ * by a postordering (via depth-first search) of the assembly tree using the
+ * AMD_postorder routine.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === clear_flag ========================================================== */
+/* ========================================================================= */
+
+static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
+{
+    Int x ;
+    if (wflg < 2 || wflg >= wbig)
+    {
+        for (x = 0 ; x < n ; x++)
+        {
+            if (W [x] != 0) W [x] = 1 ;
+        }
+        wflg = 2 ;
+    }
+    /*  at this point, W [0..n-1] < wflg holds */
+    return (wflg) ;
+}
+
+
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_2
+(
+    Int n,              /* A is n-by-n, where n > 0 */
+    Int Pe [ ],         /* Pe [0..n-1]: index in Iw of row i on input */
+    Int Iw [ ],         /* workspace of size iwlen. Iw [0..pfree-1]
+                         * holds the matrix on input */
+    Int Len [ ],        /* Len [0..n-1]: length for row/column i on input */
+    Int iwlen,          /* length of Iw. iwlen >= pfree + n */
+    Int pfree,          /* Iw [pfree ... iwlen-1] is empty on input */
+
+    /* 7 size-n workspaces, not defined on input: */
+    Int Nv [ ],         /* the size of each supernode on output */
+    Int Next [ ],       /* the output inverse permutation */
+    Int Last [ ],       /* the output permutation */
+    Int Head [ ],
+    Int Elen [ ],       /* the size columns of L for each supernode */
+    Int Degree [ ],
+    Int W [ ],
+
+    /* control parameters and output statistics */
+    double Control [ ], /* array of size AMD_CONTROL */
+    double Info [ ]     /* array of size AMD_INFO */
+)
+{
+
+/*
+ * Given a representation of the nonzero pattern of a symmetric matrix, A,
+ * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
+ * degree ordering to compute a pivot order such that the introduction of
+ * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low.  At each
+ * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
+ * upper-bound on the external degree.  This routine can optionally perform
+ * aggresive absorption (as done by MC47B in the Harwell Subroutine
+ * Library).
+ *
+ * The approximate degree algorithm implemented here is the symmetric analog of
+ * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
+ * MultiFrontal PACKage, both by Davis and Duff).  The routine is based on the
+ * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
+ *
+ * This routine is a translation of the original AMDBAR and MC47B routines,
+ * in Fortran, with the following modifications:
+ *
+ * (1) dense rows/columns are removed prior to ordering the matrix, and placed
+ *      last in the output order.  The presence of a dense row/column can
+ *      increase the ordering time by up to O(n^2), unless they are removed
+ *      prior to ordering.
+ *
+ * (2) the minimum degree ordering is followed by a postordering (depth-first
+ *      search) of the assembly tree.  Note that mass elimination (discussed
+ *      below) combined with the approximate degree update can lead to the mass
+ *      elimination of nodes with lower exact degree than the current pivot
+ *      element.  No additional fill-in is caused in the representation of the
+ *      Schur complement.  The mass-eliminated nodes merge with the current
+ *      pivot element.  They are ordered prior to the current pivot element.
+ *      Because they can have lower exact degree than the current element, the
+ *      merger of two or more of these nodes in the current pivot element can
+ *      lead to a single element that is not a "fundamental supernode".  The
+ *      diagonal block can have zeros in it.  Thus, the assembly tree used here
+ *      is not guaranteed to be the precise supernodal elemination tree (with
+ *      "funadmental" supernodes), and the postordering performed by this
+ *      routine is not guaranteed to be a precise postordering of the
+ *      elimination tree.
+ *
+ * (3) input parameters are added, to control aggressive absorption and the
+ *      detection of "dense" rows/columns of A.
+ *
+ * (4) additional statistical information is returned, such as the number of
+ *      nonzeros in L, and the flop counts for subsequent LDL' and LU
+ *      factorizations.  These are slight upper bounds, because of the mass
+ *      elimination issue discussed above.
+ *
+ * (5) additional routines are added to interface this routine to MATLAB
+ *      to provide a simple C-callable user-interface, to check inputs for
+ *      errors, compute the symmetry of the pattern of A and the number of
+ *      nonzeros in each row/column of A+A', to compute the pattern of A+A',
+ *      to perform the assembly tree postordering, and to provide debugging
+ *      ouput.  Many of these functions are also provided by the Fortran
+ *      Harwell Subroutine Library routine MC47A.
+ *
+ * (6) both int and UF_long versions are provided.  In the descriptions below
+ *      and integer is and int or UF_long depending on which version is
+ *      being used.
+
+ **********************************************************************
+ ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+ **********************************************************************
+ ** If you want error checking, a more versatile input format, and a **
+ ** simpler user interface, use amd_order or amd_l_order instead.    **
+ ** This routine is not meant to be user-callable.                   **
+ **********************************************************************
+
+ * ----------------------------------------------------------------------------
+ * References:
+ * ----------------------------------------------------------------------------
+ *
+ *  [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
+ *      method for sparse LU factorization", SIAM J. Matrix Analysis and
+ *      Applications, vol. 18, no. 1, pp. 140-158.  Discusses UMFPACK / MA38,
+ *      which first introduced the approximate minimum degree used by this
+ *      routine.
+ *
+ *  [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
+ *      minimum degree ordering algorithm," SIAM J. Matrix Analysis and
+ *      Applications, vol. 17, no. 4, pp. 886-905, 1996.  Discusses AMDBAR and
+ *      MC47B, which are the Fortran versions of this routine.
+ *
+ *  [3] Alan George and Joseph Liu, "The evolution of the minimum degree
+ *      ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
+ *      We list below the features mentioned in that paper that this code
+ *      includes:
+ *
+ *      mass elimination:
+ *          Yes.  MA27 relied on supervariable detection for mass elimination.
+ *
+ *      indistinguishable nodes:
+ *          Yes (we call these "supervariables").  This was also in the MA27
+ *          code - although we modified the method of detecting them (the
+ *          previous hash was the true degree, which we no longer keep track
+ *          of).  A supervariable is a set of rows with identical nonzero
+ *          pattern.  All variables in a supervariable are eliminated together.
+ *          Each supervariable has as its numerical name that of one of its
+ *          variables (its principal variable).
+ *
+ *      quotient graph representation:
+ *          Yes.  We use the term "element" for the cliques formed during
+ *          elimination.  This was also in the MA27 code.  The algorithm can
+ *          operate in place, but it will work more efficiently if given some
+ *          "elbow room."
+ *
+ *      element absorption:
+ *          Yes.  This was also in the MA27 code.
+ *
+ *      external degree:
+ *          Yes.  The MA27 code was based on the true degree.
+ *
+ *      incomplete degree update and multiple elimination:
+ *          No.  This was not in MA27, either.  Our method of degree update
+ *          within MC47B is element-based, not variable-based.  It is thus
+ *          not well-suited for use with incomplete degree update or multiple
+ *          elimination.
+ *
+ * Authors, and Copyright (C) 2004 by:
+ * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
+ *
+ * Acknowledgements: This work (and the UMFPACK package) was supported by the
+ * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
+ * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
+ * which forms the basis of AMD, was developed while Tim Davis was supported by
+ * CERFACS (Toulouse, France) in a post-doctoral position.  This C version, and
+ * the etree postorder, were written while Tim Davis was on sabbatical at
+ * Stanford University and Lawrence Berkeley National Laboratory.
+
+ * ----------------------------------------------------------------------------
+ * INPUT ARGUMENTS (unaltered):
+ * ----------------------------------------------------------------------------
+
+ * n:  The matrix order.  Restriction:  n >= 1.
+ *
+ * iwlen:  The size of the Iw array.  On input, the matrix is stored in
+ *      Iw [0..pfree-1].  However, Iw [0..iwlen-1] should be slightly larger
+ *      than what is required to hold the matrix, at least iwlen >= pfree + n.
+ *      Otherwise, excessive compressions will take place.  The recommended
+ *      value of iwlen is 1.2 * pfree + n, which is the value used in the
+ *      user-callable interface to this routine (amd_order.c).  The algorithm
+ *      will not run at all if iwlen < pfree.  Restriction: iwlen >= pfree + n.
+ *      Note that this is slightly more restrictive than the actual minimum
+ *      (iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
+ *      Thus, this routine enforces a bare minimum elbow room of size n.
+ *
+ * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
+ *      and the matrix is stored in Iw [0..pfree-1].  During execution,
+ *      additional data is placed in Iw, and pfree is modified so that
+ *      Iw [pfree..iwlen-1] is always the unused part of Iw.
+ *
+ * Control:  A double array of size AMD_CONTROL containing input parameters
+ *      that affect how the ordering is computed.  If NULL, then default
+ *      settings are used.
+ *
+ *      Control [AMD_DENSE] is used to determine whether or not a given input
+ *      row is "dense".  A row is "dense" if the number of entries in the row
+ *      exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
+ *      fewer entries are never considered "dense".  To turn off the detection
+ *      of dense rows, set Control [AMD_DENSE] to a negative number, or to a
+ *      number larger than sqrt (n).  The default value of Control [AMD_DENSE]
+ *      is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
+ *
+ *      Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
+ *      absorption is to be performed.  If nonzero, then aggressive absorption
+ *      is performed (this is the default).
+
+ * ----------------------------------------------------------------------------
+ * INPUT/OUPUT ARGUMENTS:
+ * ----------------------------------------------------------------------------
+ *
+ * Pe:  An integer array of size n.  On input, Pe [i] is the index in Iw of
+ *      the start of row i.  Pe [i] is ignored if row i has no off-diagonal
+ *      entries.  Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
+ *      rows.
+ *
+ *      During execution, it is used for both supervariables and elements:
+ *
+ *      Principal supervariable i:  index into Iw of the description of
+ *          supervariable i.  A supervariable represents one or more rows of
+ *          the matrix with identical nonzero pattern.  In this case,
+ *          Pe [i] >= 0.
+ *
+ *      Non-principal supervariable i:  if i has been absorbed into another
+ *          supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
+ *          as (-(j)-2).  Row j has the same pattern as row i.  Note that j
+ *          might later be absorbed into another supervariable j2, in which
+ *          case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
+ *          < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
+ *
+ *      Unabsorbed element e:  the index into Iw of the description of element
+ *          e, if e has not yet been absorbed by a subsequent element.  Element
+ *          e is created when the supervariable of the same name is selected as
+ *          the pivot.  In this case, Pe [i] >= 0.
+ *
+ *      Absorbed element e:  if element e is absorbed into element e2, then
+ *          Pe [e] = FLIP (e2).  This occurs when the pattern of e (which we
+ *          refer to as Le) is found to be a subset of the pattern of e2 (that
+ *          is, Le2).  In this case, Pe [i] < EMPTY.  If element e is "null"
+ *          (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
+ *          and e is the root of an assembly subtree (or the whole tree if
+ *          there is just one such root).
+ *
+ *      Dense variable i:  if i is "dense", then Pe [i] = EMPTY.
+ *
+ *      On output, Pe holds the assembly tree/forest, which implicitly
+ *      represents a pivot order with identical fill-in as the actual order
+ *      (via a depth-first search of the tree), as follows.  If Nv [i] > 0,
+ *      then i represents a node in the assembly tree, and the parent of i is
+ *      Pe [i], or EMPTY if i is a root.  If Nv [i] = 0, then (i, Pe [i])
+ *      represents an edge in a subtree, the root of which is a node in the
+ *      assembly tree.  Note that i refers to a row/column in the original
+ *      matrix, not the permuted matrix.
+ *
+ * Info:  A double array of size AMD_INFO.  If present, (that is, not NULL),
+ *      then statistics about the ordering are returned in the Info array.
+ *      See amd.h for a description.
+
+ * ----------------------------------------------------------------------------
+ * INPUT/MODIFIED (undefined on output):
+ * ----------------------------------------------------------------------------
+ *
+ * Len:  An integer array of size n.  On input, Len [i] holds the number of
+ *      entries in row i of the matrix, excluding the diagonal.  The contents
+ *      of Len are undefined on output.
+ *
+ * Iw:  An integer array of size iwlen.  On input, Iw [0..pfree-1] holds the
+ *      description of each row i in the matrix.  The matrix must be symmetric,
+ *      and both upper and lower triangular parts must be present.  The
+ *      diagonal must not be present.  Row i is held as follows:
+ *
+ *          Len [i]:  the length of the row i data structure in the Iw array.
+ *          Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
+ *              the list of column indices for nonzeros in row i (simple
+ *              supervariables), excluding the diagonal.  All supervariables
+ *              start with one row/column each (supervariable i is just row i).
+ *              If Len [i] is zero on input, then Pe [i] is ignored on input.
+ *
+ *          Note that the rows need not be in any particular order, and there
+ *          may be empty space between the rows.
+ *
+ *      During execution, the supervariable i experiences fill-in.  This is
+ *      represented by placing in i a list of the elements that cause fill-in
+ *      in supervariable i:
+ *
+ *          Len [i]:  the length of supervariable i in the Iw array.
+ *          Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
+ *              the list of elements that contain i.  This list is kept short
+ *              by removing absorbed elements.
+ *          Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
+ *              the list of supervariables in i.  This list is kept short by
+ *              removing nonprincipal variables, and any entry j that is also
+ *              contained in at least one of the elements (j in Le) in the list
+ *              for i (e in row i).
+ *
+ *      When supervariable i is selected as pivot, we create an element e of
+ *      the same name (e=i):
+ *
+ *          Len [e]:  the length of element e in the Iw array.
+ *          Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
+ *              the list of supervariables in element e.
+ *
+ *      An element represents the fill-in that occurs when supervariable i is
+ *      selected as pivot (which represents the selection of row i and all
+ *      non-principal variables whose principal variable is i).  We use the
+ *      term Le to denote the set of all supervariables in element e.  Absorbed
+ *      supervariables and elements are pruned from these lists when
+ *      computationally convenient.
+ *
+ *  CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+ *  The contents of Iw are undefined on output.
+
+ * ----------------------------------------------------------------------------
+ * OUTPUT (need not be set on input):
+ * ----------------------------------------------------------------------------
+ *
+ * Nv:  An integer array of size n.  During execution, ABS (Nv [i]) is equal to
+ *      the number of rows that are represented by the principal supervariable
+ *      i.  If i is a nonprincipal or dense variable, then Nv [i] = 0.
+ *      Initially, Nv [i] = 1 for all i.  Nv [i] < 0 signifies that i is a
+ *      principal variable in the pattern Lme of the current pivot element me.
+ *      After element me is constructed, Nv [i] is set back to a positive
+ *      value.
+ *
+ *      On output, Nv [i] holds the number of pivots represented by super
+ *      row/column i of the original matrix, or Nv [i] = 0 for non-principal
+ *      rows/columns.  Note that i refers to a row/column in the original
+ *      matrix, not the permuted matrix.
+ *
+ * Elen:  An integer array of size n.  See the description of Iw above.  At the
+ *      start of execution, Elen [i] is set to zero for all rows i.  During
+ *      execution, Elen [i] is the number of elements in the list for
+ *      supervariable i.  When e becomes an element, Elen [e] = FLIP (esize) is
+ *      set, where esize is the size of the element (the number of pivots, plus
+ *      the number of nonpivotal entries).  Thus Elen [e] < EMPTY.
+ *      Elen (i) = EMPTY set when variable i becomes nonprincipal.
+ *
+ *      For variables, Elen (i) >= EMPTY holds until just before the
+ *      postordering and permutation vectors are computed.  For elements,
+ *      Elen [e] < EMPTY holds.
+ *
+ *      On output, Elen [i] is the degree of the row/column in the Cholesky
+ *      factorization of the permuted matrix, corresponding to the original row
+ *      i, if i is a super row/column.  It is equal to EMPTY if i is
+ *      non-principal.  Note that i refers to a row/column in the original
+ *      matrix, not the permuted matrix.
+ *
+ *      Note that the contents of Elen on output differ from the Fortran
+ *      version (Elen holds the inverse permutation in the Fortran version,
+ *      which is instead returned in the Next array in this C version,
+ *      described below).
+ *
+ * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
+ *      if i is the head of the list.  In a hash bucket, Last [i] is the hash
+ *      key for i.
+ *
+ *      Last [Head [hash]] is also used as the head of a hash bucket if
+ *      Head [hash] contains a degree list (see the description of Head,
+ *      below).
+ *
+ *      On output, Last [0..n-1] holds the permutation.  That is, if
+ *      i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
+ *      n-1).  Row Last [k] of A is the kth row in the permuted matrix, PAP'.
+ *
+ * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
+ *      i is the last in the list.  Used for two kinds of lists:  degree lists
+ *      and hash buckets (a supervariable can be in only one kind of list at a
+ *      time).
+ *
+ *      On output Next [0..n-1] holds the inverse permutation.  That is, if
+ *      k = Next [i], then row i is the kth pivot row. Row i of A appears as
+ *      the (Next[i])-th row in the permuted matrix, PAP'.
+ *
+ *      Note that the contents of Next on output differ from the Fortran
+ *      version (Next is undefined on output in the Fortran version).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL WORKSPACE (not input or output - used only during execution):
+ * ----------------------------------------------------------------------------
+ *
+ * Degree:  An integer array of size n.  If i is a supervariable, then
+ *      Degree [i] holds the current approximation of the external degree of
+ *      row i (an upper bound).  The external degree is the number of nonzeros
+ *      in row i, minus ABS (Nv [i]), the diagonal part.  The bound is equal to
+ *      the exact external degree if Elen [i] is less than or equal to two.
+ *
+ *      We also use the term "external degree" for elements e to refer to
+ *      |Le \ Lme|.  If e is an element, then Degree [e] is |Le|, which is the
+ *      degree of the off-diagonal part of the element e (not including the
+ *      diagonal part).
+ *
+ * Head:   An integer array of size n.  Head is used for degree lists.
+ *      Head [deg] is the first supervariable in a degree list.  All
+ *      supervariables i in a degree list Head [deg] have the same approximate
+ *      degree, namely, deg = Degree [i].  If the list Head [deg] is empty then
+ *      Head [deg] = EMPTY.
+ *
+ *      During supervariable detection Head [hash] also serves as a pointer to
+ *      a hash bucket.  If Head [hash] >= 0, there is a degree list of degree
+ *      hash.  The hash bucket head pointer is Last [Head [hash]].  If
+ *      Head [hash] = EMPTY, then the degree list and hash bucket are both
+ *      empty.  If Head [hash] < EMPTY, then the degree list is empty, and
+ *      FLIP (Head [hash]) is the head of the hash bucket.  After supervariable
+ *      detection is complete, all hash buckets are empty, and the
+ *      (Last [Head [hash]] = EMPTY) condition is restored for the non-empty
+ *      degree lists.
+ *
+ * W:  An integer array of size n.  The flag array W determines the status of
+ *      elements and variables, and the external degree of elements.
+ *
+ *      for elements:
+ *          if W [e] = 0, then the element e is absorbed.
+ *          if W [e] >= wflg, then W [e] - wflg is the size of the set
+ *              |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
+ *              each principal variable i that is both in the pattern of
+ *              element e and NOT in the pattern of the current pivot element,
+ *              me).
+ *          if wflg > W [e] > 0, then e is not absorbed and has not yet been
+ *              seen in the scan of the element lists in the computation of
+ *              |Le\Lme| in Scan 1 below.
+ *
+ *      for variables:
+ *          during supervariable detection, if W [j] != wflg then j is
+ *          not in the pattern of variable i.
+ *
+ *      The W array is initialized by setting W [i] = 1 for all i, and by
+ *      setting wflg = 2.  It is reinitialized if wflg becomes too large (to
+ *      ensure that wflg+n does not cause integer overflow).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL INTEGERS:
+ * ----------------------------------------------------------------------------
+ */
+
+    Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
+        jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
+        nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa,
+        dense, aggressive ;
+
+    unsigned Int hash ;     /* unsigned, so that hash % n is well defined.*/
+
+/*
+ * deg:         the degree of a variable or element
+ * degme:       size, |Lme|, of the current element, me (= Degree [me])
+ * dext:        external degree, |Le \ Lme|, of some element e
+ * lemax:       largest |Le| seen so far (called dmax in Fortran version)
+ * e:           an element
+ * elenme:      the length, Elen [me], of element list of pivotal variable
+ * eln:         the length, Elen [...], of an element list
+ * hash:        the computed value of the hash function
+ * i:           a supervariable
+ * ilast:       the entry in a link list preceding i
+ * inext:       the entry in a link list following i
+ * j:           a supervariable
+ * jlast:       the entry in a link list preceding j
+ * jnext:       the entry in a link list, or path, following j
+ * k:           the pivot order of an element or variable
+ * knt1:        loop counter used during element construction
+ * knt2:        loop counter used during element construction
+ * knt3:        loop counter used during compression
+ * lenj:        Len [j]
+ * ln:          length of a supervariable list
+ * me:          current supervariable being eliminated, and the current
+ *                  element created by eliminating that supervariable
+ * mindeg:      current minimum degree
+ * nel:         number of pivots selected so far
+ * nleft:       n - nel, the number of nonpivotal rows/columns remaining
+ * nvi:         the number of variables in a supervariable i (= Nv [i])
+ * nvj:         the number of variables in a supervariable j (= Nv [j])
+ * nvpiv:       number of pivots in current element
+ * slenme:      number of variables in variable list of pivotal variable
+ * wbig:        = INT_MAX - n for the int version, UF_long_max - n for the
+ *                  UF_long version.  wflg is not allowed to be >= wbig.
+ * we:          W [e]
+ * wflg:        used for flagging the W array.  See description of Iw.
+ * wnvi:        wflg - Nv [i]
+ * x:           either a supervariable or an element
+ *
+ * ok:          true if supervariable j can be absorbed into i
+ * ndense:      number of "dense" rows/columns
+ * dense:       rows/columns with initial degree > dense are considered "dense"
+ * aggressive:  true if aggressive absorption is being performed
+ * ncmpa:       number of garbage collections
+
+ * ----------------------------------------------------------------------------
+ * LOCAL DOUBLES, used for statistical output only (except for alpha):
+ * ----------------------------------------------------------------------------
+ */
+
+    double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
+
+/*
+ * f:           nvpiv
+ * r:           degme + nvpiv
+ * ndiv:        number of divisions for LU or LDL' factorizations
+ * s:           number of multiply-subtract pairs for LU factorization, for the
+ *                  current element me
+ * nms_lu       number of multiply-subtract pairs for LU factorization
+ * nms_ldl      number of multiply-subtract pairs for LDL' factorization
+ * dmax:        the largest number of entries in any column of L, including the
+ *                  diagonal
+ * alpha:       "dense" degree ratio
+ * lnz:         the number of nonzeros in L (excluding the diagonal)
+ * lnzme:       the number of nonzeros in L (excl. the diagonal) for the
+ *                  current element me
+
+ * ----------------------------------------------------------------------------
+ * LOCAL "POINTERS" (indices into the Iw array)
+ * ----------------------------------------------------------------------------
+*/
+
+    Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
+
+/*
+ * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
+ * Pointer) is an index into Iw, and all indices into Iw use variables starting
+ * with "p."  The only exception to this rule is the iwlen input argument.
+ *
+ * p:           pointer into lots of things
+ * p1:          Pe [i] for some variable i (start of element list)
+ * p2:          Pe [i] + Elen [i] -  1 for some variable i
+ * p3:          index of first supervariable in clean list
+ * p4:          
+ * pdst:        destination pointer, for compression
+ * pend:        end of memory to compress
+ * pj:          pointer into an element or variable
+ * pme:         pointer into the current element (pme1...pme2)
+ * pme1:        the current element, me, is stored in Iw [pme1...pme2]
+ * pme2:        the end of the current element
+ * pn:          pointer into a "clean" variable, also used to compress
+ * psrc:        source pointer, for compression
+*/
+
+/* ========================================================================= */
+/*  INITIALIZATIONS */
+/* ========================================================================= */
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is actually required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be slow.  For better performance, at least
+     * size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+    ASSERT (n > 0) ;
+
+    /* initialize output statistics */
+    lnz = 0 ;
+    ndiv = 0 ;
+    nms_lu = 0 ;
+    nms_ldl = 0 ;
+    dmax = 1 ;
+    me = EMPTY ;
+
+    mindeg = 0 ;
+    ncmpa = 0 ;
+    nel = 0 ;
+    lemax = 0 ;
+
+    /* get control parameters */
+    if (Control != (double *) NULL)
+    {
+        alpha = Control [AMD_DENSE] ;
+        aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
+    }
+    else
+    {
+        alpha = AMD_DEFAULT_DENSE ;
+        aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+    /* Note: if alpha is NaN, this is undefined: */
+    if (alpha < 0)
+    {
+        /* only remove completely dense rows/columns */
+        dense = n-2 ;
+    }
+    else
+    {
+        dense = alpha * sqrt ((double) n) ;
+    }
+    dense = MAX (16, dense) ;
+    dense = MIN (n,  dense) ;
+    AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n",
+        alpha, aggressive)) ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+        Last [i] = EMPTY ;
+        Head [i] = EMPTY ;
+        Next [i] = EMPTY ;
+        /* if separate Hhead array is used for hash buckets: *
+        Hhead [i] = EMPTY ;
+        */
+        Nv [i] = 1 ;
+        W [i] = 1 ;
+        Elen [i] = 0 ;
+        Degree [i] = Len [i] ;
+    }
+
+#ifndef NDEBUG
+    AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ;
+    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
+                Head, Elen, Degree, W, -1) ;
+#endif
+
+    /* initialize wflg */
+    wbig = Int_MAX - n ;
+    wflg = clear_flag (0, wbig, W, n) ;
+
+    /* --------------------------------------------------------------------- */
+    /* initialize degree lists and eliminate dense and empty rows */
+    /* --------------------------------------------------------------------- */
+
+    ndense = 0 ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+        deg = Degree [i] ;
+        ASSERT (deg >= 0 && deg < n) ;
+        if (deg == 0)
+        {
+
+            /* -------------------------------------------------------------
+             * we have a variable that can be eliminated at once because
+             * there is no off-diagonal non-zero in its row.  Note that
+             * Nv [i] = 1 for an empty variable i.  It is treated just
+             * the same as an eliminated element i.
+             * ------------------------------------------------------------- */
+
+            Elen [i] = FLIP (1) ;
+            nel++ ;
+            Pe [i] = EMPTY ;
+            W [i] = 0 ;
+
+        }
+        else if (deg > dense)
+        {
+
+            /* -------------------------------------------------------------
+             * Dense variables are not treated as elements, but as unordered,
+             * non-principal variables that have no parent.  They do not take
+             * part in the postorder, since Nv [i] = 0.  Note that the Fortran
+             * version does not have this option.
+             * ------------------------------------------------------------- */
+
+            AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
+            ndense++ ;
+            Nv [i] = 0 ;                /* do not postorder this node */
+            Elen [i] = EMPTY ;
+            nel++ ;
+            Pe [i] = EMPTY ;
+
+        }
+        else
+        {
+
+            /* -------------------------------------------------------------
+             * place i in the degree list corresponding to its degree
+             * ------------------------------------------------------------- */
+
+            inext = Head [deg] ;
+            ASSERT (inext >= EMPTY && inext < n) ;
+            if (inext != EMPTY) Last [inext] = i ;
+            Next [i] = inext ;
+            Head [deg] = i ;
+
+        }
+    }
+
+/* ========================================================================= */
+/* WHILE (selecting pivots) DO */
+/* ========================================================================= */
+
+    while (nel < n)
+    {
+
+#ifndef NDEBUG
+        AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+        if (AMD_debug >= 2)
+        {
+            AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
+                    Last, Head, Elen, Degree, W, nel) ;
+        }
+#endif
+
+/* ========================================================================= */
+/* GET PIVOT OF MINIMUM DEGREE */
+/* ========================================================================= */
+
+        /* ----------------------------------------------------------------- */
+        /* find next supervariable for elimination */
+        /* ----------------------------------------------------------------- */
+
+        ASSERT (mindeg >= 0 && mindeg < n) ;
+        for (deg = mindeg ; deg < n ; deg++)
+        {
+            me = Head [deg] ;
+            if (me != EMPTY) break ;
+        }
+        mindeg = deg ;
+        ASSERT (me >= 0 && me < n) ;
+        AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
+
+        /* ----------------------------------------------------------------- */
+        /* remove chosen variable from link list */
+        /* ----------------------------------------------------------------- */
+
+        inext = Next [me] ;
+        ASSERT (inext >= EMPTY && inext < n) ;
+        if (inext != EMPTY) Last [inext] = EMPTY ;
+        Head [deg] = inext ;
+
+        /* ----------------------------------------------------------------- */
+        /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
+        /* place me itself as the first in this set. */
+        /* ----------------------------------------------------------------- */
+
+        elenme = Elen [me] ;
+        nvpiv = Nv [me] ;
+        ASSERT (nvpiv > 0) ;
+        nel += nvpiv ;
+
+/* ========================================================================= */
+/* CONSTRUCT NEW ELEMENT */
+/* ========================================================================= */
+
+        /* -----------------------------------------------------------------
+         * At this point, me is the pivotal supervariable.  It will be
+         * converted into the current element.  Scan list of the pivotal
+         * supervariable, me, setting tree pointers and constructing new list
+         * of supervariables for the new element, me.  p is a pointer to the
+         * current position in the old list.
+         * ----------------------------------------------------------------- */
+
+        /* flag the variable "me" as being in Lme by negating Nv [me] */
+        Nv [me] = -nvpiv ;
+        degme = 0 ;
+        ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+        if (elenme == 0)
+        {
+
+            /* ------------------------------------------------------------- */
+            /* construct the new element in place */
+            /* ------------------------------------------------------------- */
+
+            pme1 = Pe [me] ;
+            pme2 = pme1 - 1 ;
+
+            for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
+            {
+                i = Iw [p] ;
+                ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
+                nvi = Nv [i] ;
+                if (nvi > 0)
+                {
+
+                    /* ----------------------------------------------------- */
+                    /* i is a principal variable not yet placed in Lme. */
+                    /* store i in new list */
+                    /* ----------------------------------------------------- */
+
+                    /* flag i as being in Lme by negating Nv [i] */
+                    degme += nvi ;
+                    Nv [i] = -nvi ;
+                    Iw [++pme2] = i ;
+
+                    /* ----------------------------------------------------- */
+                    /* remove variable i from degree list. */
+                    /* ----------------------------------------------------- */
+
+                    ilast = Last [i] ;
+                    inext = Next [i] ;
+                    ASSERT (ilast >= EMPTY && ilast < n) ;
+                    ASSERT (inext >= EMPTY && inext < n) ;
+                    if (inext != EMPTY) Last [inext] = ilast ;
+                    if (ilast != EMPTY)
+                    {
+                        Next [ilast] = inext ;
+                    }
+                    else
+                    {
+                        /* i is at the head of the degree list */
+                        ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+                        Head [Degree [i]] = inext ;
+                    }
+                }
+            }
+        }
+        else
+        {
+
+            /* ------------------------------------------------------------- */
+            /* construct the new element in empty space, Iw [pfree ...] */
+            /* ------------------------------------------------------------- */
+
+            p = Pe [me] ;
+            pme1 = pfree ;
+            slenme = Len [me] - elenme ;
+
+            for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
+            {
+
+                if (knt1 > elenme)
+                {
+                    /* search the supervariables in me. */
+                    e = me ;
+                    pj = p ;
+                    ln = slenme ;
+                    AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
+                }
+                else
+                {
+                    /* search the elements in me. */
+                    e = Iw [p++] ;
+                    ASSERT (e >= 0 && e < n) ;
+                    pj = Pe [e] ;
+                    ln = Len [e] ;
+                    AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
+                    ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
+                }
+                ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
+
+                /* ---------------------------------------------------------
+                 * search for different supervariables and add them to the
+                 * new list, compressing when necessary. this loop is
+                 * executed once for each element in the list and once for
+                 * all the supervariables in the list.
+                 * --------------------------------------------------------- */
+
+                for (knt2 = 1 ; knt2 <= ln ; knt2++)
+                {
+                    i = Iw [pj++] ;
+                    ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
+                    nvi = Nv [i] ;
+                    AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
+                                i, Elen [i], Nv [i], wflg)) ;
+
+                    if (nvi > 0)
+                    {
+
+                        /* ------------------------------------------------- */
+                        /* compress Iw, if necessary */
+                        /* ------------------------------------------------- */
+
+                        if (pfree >= iwlen)
+                        {
+
+                            AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
+
+                            /* prepare for compressing Iw by adjusting pointers
+                             * and lengths so that the lists being searched in
+                             * the inner and outer loops contain only the
+                             * remaining entries. */
+
+                            Pe [me] = p ;
+                            Len [me] -= knt1 ;
+                            /* check if nothing left of supervariable me */
+                            if (Len [me] == 0) Pe [me] = EMPTY ;
+                            Pe [e] = pj ;
+                            Len [e] = ln - knt2 ;
+                            /* nothing left of element e */
+                            if (Len [e] == 0) Pe [e] = EMPTY ;
+
+                            ncmpa++ ;   /* one more garbage collection */
+
+                            /* store first entry of each object in Pe */
+                            /* FLIP the first entry in each object */
+                            for (j = 0 ; j < n ; j++)
+                            {
+                                pn = Pe [j] ;
+                                if (pn >= 0)
+                                {
+                                    ASSERT (pn >= 0 && pn < iwlen) ;
+                                    Pe [j] = Iw [pn] ;
+                                    Iw [pn] = FLIP (j) ;
+                                }
+                            }
+
+                            /* psrc/pdst point to source/destination */
+                            psrc = 0 ;
+                            pdst = 0 ;
+                            pend = pme1 - 1 ;
+
+                            while (psrc <= pend)
+                            {
+                                /* search for next FLIP'd entry */
+                                j = FLIP (Iw [psrc++]) ;
+                                if (j >= 0)
+                                {
+                                    AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
+                                    Iw [pdst] = Pe [j] ;
+                                    Pe [j] = pdst++ ;
+                                    lenj = Len [j] ;
+                                    /* copy from source to destination */
+                                    for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
+                                    {
+                                        Iw [pdst++] = Iw [psrc++] ;
+                                    }
+                                }
+                            }
+
+                            /* move the new partially-constructed element */
+                            p1 = pdst ;
+                            for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
+                            {
+                                Iw [pdst++] = Iw [psrc] ;
+                            }
+                            pme1 = p1 ;
+                            pfree = pdst ;
+                            pj = Pe [e] ;
+                            p = Pe [me] ;
+
+                        }
+
+                        /* ------------------------------------------------- */
+                        /* i is a principal variable not yet placed in Lme */
+                        /* store i in new list */
+                        /* ------------------------------------------------- */
+
+                        /* flag i as being in Lme by negating Nv [i] */
+                        degme += nvi ;
+                        Nv [i] = -nvi ;
+                        Iw [pfree++] = i ;
+                        AMD_DEBUG2 (("     s: "ID"     nv "ID"\n", i, Nv [i]));
+
+                        /* ------------------------------------------------- */
+                        /* remove variable i from degree link list */
+                        /* ------------------------------------------------- */
+
+                        ilast = Last [i] ;
+                        inext = Next [i] ;
+                        ASSERT (ilast >= EMPTY && ilast < n) ;
+                        ASSERT (inext >= EMPTY && inext < n) ;
+                        if (inext != EMPTY) Last [inext] = ilast ;
+                        if (ilast != EMPTY)
+                        {
+                            Next [ilast] = inext ;
+                        }
+                        else
+                        {
+                            /* i is at the head of the degree list */
+                            ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+                            Head [Degree [i]] = inext ;
+                        }
+                    }
+                }
+
+                if (e != me)
+                {
+                    /* set tree pointer and flag to indicate element e is
+                     * absorbed into new element me (the parent of e is me) */
+                    AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
+                    Pe [e] = FLIP (me) ;
+                    W [e] = 0 ;
+                }
+            }
+
+            pme2 = pfree - 1 ;
+        }
+
+        /* ----------------------------------------------------------------- */
+        /* me has now been converted into an element in Iw [pme1..pme2] */
+        /* ----------------------------------------------------------------- */
+
+        /* degme holds the external degree of new element */
+        Degree [me] = degme ;
+        Pe [me] = pme1 ;
+        Len [me] = pme2 - pme1 + 1 ;
+        ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+        Elen [me] = FLIP (nvpiv + degme) ;
+        /* FLIP (Elen (me)) is now the degree of pivot (including
+         * diagonal part). */
+
+#ifndef NDEBUG
+        AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
+        for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
+        AMD_DEBUG3 (("\n")) ;
+#endif
+
+        /* ----------------------------------------------------------------- */
+        /* make sure that wflg is not too large. */
+        /* ----------------------------------------------------------------- */
+
+        /* With the current value of wflg, wflg+n must not cause integer
+         * overflow */
+
+        wflg = clear_flag (wflg, wbig, W, n) ;
+
+/* ========================================================================= */
+/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
+/* ========================================================================= */
+
+        /* -----------------------------------------------------------------
+         * Scan 1:  compute the external degrees of previous elements with
+         * respect to the current element.  That is:
+         *       (W [e] - wflg) = |Le \ Lme|
+         * for each element e that appears in any supervariable in Lme.  The
+         * notation Le refers to the pattern (list of supervariables) of a
+         * previous element e, where e is not yet absorbed, stored in
+         * Iw [Pe [e] + 1 ... Pe [e] + Len [e]].  The notation Lme
+         * refers to the pattern of the current element (stored in
+         * Iw [pme1..pme2]).   If aggressive absorption is enabled, and
+         * (W [e] - wflg) becomes zero, then the element e will be absorbed
+         * in Scan 2.
+         * ----------------------------------------------------------------- */
+
+        AMD_DEBUG2 (("me: ")) ;
+        for (pme = pme1 ; pme <= pme2 ; pme++)
+        {
+            i = Iw [pme] ;
+            ASSERT (i >= 0 && i < n) ;
+            eln = Elen [i] ;
+            AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
+            if (eln > 0)
+            {
+                /* note that Nv [i] has been negated to denote i in Lme: */
+                nvi = -Nv [i] ;
+                ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
+                wnvi = wflg - nvi ;
+                for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
+                {
+                    e = Iw [p] ;
+                    ASSERT (e >= 0 && e < n) ;
+                    we = W [e] ;
+                    AMD_DEBUG4 (("    e "ID" we "ID" ", e, we)) ;
+                    if (we >= wflg)
+                    {
+                        /* unabsorbed element e has been seen in this loop */
+                        AMD_DEBUG4 (("    unabsorbed, first time seen")) ;
+                        we -= nvi ;
+                    }
+                    else if (we != 0)
+                    {
+                        /* e is an unabsorbed element */
+                        /* this is the first we have seen e in all of Scan 1 */
+                        AMD_DEBUG4 (("    unabsorbed")) ;
+                        we = Degree [e] + wnvi ;
+                    }
+                    AMD_DEBUG4 (("\n")) ;
+                    W [e] = we ;
+                }
+            }
+        }
+        AMD_DEBUG2 (("\n")) ;
+
+/* ========================================================================= */
+/* DEGREE UPDATE AND ELEMENT ABSORPTION */
+/* ========================================================================= */
+
+        /* -----------------------------------------------------------------
+         * Scan 2:  for each i in Lme, sum up the degree of Lme (which is
+         * degme), plus the sum of the external degrees of each Le for the
+         * elements e appearing within i, plus the supervariables in i.
+         * Place i in hash list.
+         * ----------------------------------------------------------------- */
+
+        for (pme = pme1 ; pme <= pme2 ; pme++)
+        {
+            i = Iw [pme] ;
+            ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
+            AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
+            p1 = Pe [i] ;
+            p2 = p1 + Elen [i] - 1 ;
+            pn = p1 ;
+            hash = 0 ;
+            deg = 0 ;
+            ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
+
+            /* ------------------------------------------------------------- */
+            /* scan the element list associated with supervariable i */
+            /* ------------------------------------------------------------- */
+
+            /* UMFPACK/MA38-style approximate degree: */
+            if (aggressive)
+            {
+                for (p = p1 ; p <= p2 ; p++)
+                {
+                    e = Iw [p] ;
+                    ASSERT (e >= 0 && e < n) ;
+                    we = W [e] ;
+                    if (we != 0)
+                    {
+                        /* e is an unabsorbed element */
+                        /* dext = | Le \ Lme | */
+                        dext = we - wflg ;
+                        if (dext > 0)
+                        {
+                            deg += dext ;
+                            Iw [pn++] = e ;
+                            hash += e ;
+                            AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+                        }
+                        else
+                        {
+                            /* external degree of e is zero, absorb e into me*/
+                            AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
+                                e, me)) ;
+                            ASSERT (dext == 0) ;
+                            Pe [e] = FLIP (me) ;
+                            W [e] = 0 ;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (p = p1 ; p <= p2 ; p++)
+                {
+                    e = Iw [p] ;
+                    ASSERT (e >= 0 && e < n) ;
+                    we = W [e] ;
+                    if (we != 0)
+                    {
+                        /* e is an unabsorbed element */
+                        dext = we - wflg ;
+                        ASSERT (dext >= 0) ;
+                        deg += dext ;
+                        Iw [pn++] = e ;
+                        hash += e ;
+                        AMD_DEBUG4 (("  e: "ID" hash = "ID"\n",e,hash)) ;
+                    }
+                }
+            }
+
+            /* count the number of elements in i (including me): */
+            Elen [i] = pn - p1 + 1 ;
+
+            /* ------------------------------------------------------------- */
+            /* scan the supervariables in the list associated with i */
+            /* ------------------------------------------------------------- */
+
+            /* The bulk of the AMD run time is typically spent in this loop,
+             * particularly if the matrix has many dense rows that are not
+             * removed prior to ordering. */
+            p3 = pn ;
+            p4 = p1 + Len [i] ;
+            for (p = p2 + 1 ; p < p4 ; p++)
+            {
+                j = Iw [p] ;
+                ASSERT (j >= 0 && j < n) ;
+                nvj = Nv [j] ;
+                if (nvj > 0)
+                {
+                    /* j is unabsorbed, and not in Lme. */
+                    /* add to degree and add to new list */
+                    deg += nvj ;
+                    Iw [pn++] = j ;
+                    hash += j ;
+                    AMD_DEBUG4 (("  s: "ID" hash "ID" Nv[j]= "ID"\n",
+                                j, hash, nvj)) ;
+                }
+            }
+
+            /* ------------------------------------------------------------- */
+            /* update the degree and check for mass elimination */
+            /* ------------------------------------------------------------- */
+
+            /* with aggressive absorption, deg==0 is identical to the
+             * Elen [i] == 1 && p3 == pn test, below. */
+            ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
+
+            if (Elen [i] == 1 && p3 == pn)
+            {
+
+                /* --------------------------------------------------------- */
+                /* mass elimination */
+                /* --------------------------------------------------------- */
+
+                /* There is nothing left of this node except for an edge to
+                 * the current pivot element.  Elen [i] is 1, and there are
+                 * no variables adjacent to node i.  Absorb i into the
+                 * current pivot element, me.  Note that if there are two or
+                 * more mass eliminations, fillin due to mass elimination is
+                 * possible within the nvpiv-by-nvpiv pivot block.  It is this
+                 * step that causes AMD's analysis to be an upper bound.
+                 *
+                 * The reason is that the selected pivot has a lower
+                 * approximate degree than the true degree of the two mass
+                 * eliminated nodes.  There is no edge between the two mass
+                 * eliminated nodes.  They are merged with the current pivot
+                 * anyway.
+                 *
+                 * No fillin occurs in the Schur complement, in any case,
+                 * and this effect does not decrease the quality of the
+                 * ordering itself, just the quality of the nonzero and
+                 * flop count analysis.  It also means that the post-ordering
+                 * is not an exact elimination tree post-ordering. */
+
+                AMD_DEBUG1 (("  MASS i "ID" => parent e "ID"\n", i, me)) ;
+                Pe [i] = FLIP (me) ;
+                nvi = -Nv [i] ;
+                degme -= nvi ;
+                nvpiv += nvi ;
+                nel += nvi ;
+                Nv [i] = 0 ;
+                Elen [i] = EMPTY ;
+
+            }
+            else
+            {
+
+                /* --------------------------------------------------------- */
+                /* update the upper-bound degree of i */
+                /* --------------------------------------------------------- */
+
+                /* the following degree does not yet include the size
+                 * of the current element, which is added later: */
+
+                Degree [i] = MIN (Degree [i], deg) ;
+
+                /* --------------------------------------------------------- */
+                /* add me to the list for i */
+                /* --------------------------------------------------------- */
+
+                /* move first supervariable to end of list */
+                Iw [pn] = Iw [p3] ;
+                /* move first element to end of element part of list */
+                Iw [p3] = Iw [p1] ;
+                /* add new element, me, to front of list. */
+                Iw [p1] = me ;
+                /* store the new length of the list in Len [i] */
+                Len [i] = pn - p1 + 1 ;
+
+                /* --------------------------------------------------------- */
+                /* place in hash bucket.  Save hash key of i in Last [i]. */
+                /* --------------------------------------------------------- */
+
+                /* NOTE: this can fail if hash is negative, because the ANSI C
+                 * standard does not define a % b when a and/or b are negative.
+                 * That's why hash is defined as an unsigned Int, to avoid this
+                 * problem. */
+                hash = hash % n ;
+                ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
+
+                /* if the Hhead array is not used: */
+                j = Head [hash] ;
+                if (j <= EMPTY)
+                {
+                    /* degree list is empty, hash head is FLIP (j) */
+                    Next [i] = FLIP (j) ;
+                    Head [hash] = FLIP (i) ;
+                }
+                else
+                {
+                    /* degree list is not empty, use Last [Head [hash]] as
+                     * hash head. */
+                    Next [i] = Last [j] ;
+                    Last [j] = i ;
+                }
+
+                /* if a separate Hhead array is used: *
+                Next [i] = Hhead [hash] ;
+                Hhead [hash] = i ;
+                */
+
+                Last [i] = hash ;
+            }
+        }
+
+        Degree [me] = degme ;
+
+        /* ----------------------------------------------------------------- */
+        /* Clear the counter array, W [...], by incrementing wflg. */
+        /* ----------------------------------------------------------------- */
+
+        /* make sure that wflg+n does not cause integer overflow */
+        lemax =  MAX (lemax, degme) ;
+        wflg += lemax ;
+        wflg = clear_flag (wflg, wbig, W, n) ;
+        /*  at this point, W [0..n-1] < wflg holds */
+
+/* ========================================================================= */
+/* SUPERVARIABLE DETECTION */
+/* ========================================================================= */
+
+        AMD_DEBUG1 (("Detecting supervariables:\n")) ;
+        for (pme = pme1 ; pme <= pme2 ; pme++)
+        {
+            i = Iw [pme] ;
+            ASSERT (i >= 0 && i < n) ;
+            AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
+            if (Nv [i] < 0)
+            {
+                /* i is a principal variable in Lme */
+
+                /* ---------------------------------------------------------
+                 * examine all hash buckets with 2 or more variables.  We do
+                 * this by examing all unique hash keys for supervariables in
+                 * the pattern Lme of the current element, me
+                 * --------------------------------------------------------- */
+
+                /* let i = head of hash bucket, and empty the hash bucket */
+                ASSERT (Last [i] >= 0 && Last [i] < n) ;
+                hash = Last [i] ;
+
+                /* if Hhead array is not used: */
+                j = Head [hash] ;
+                if (j == EMPTY)
+                {
+                    /* hash bucket and degree list are both empty */
+                    i = EMPTY ;
+                }
+                else if (j < EMPTY)
+                {
+                    /* degree list is empty */
+                    i = FLIP (j) ;
+                    Head [hash] = EMPTY ;
+                }
+                else
+                {
+                    /* degree list is not empty, restore Last [j] of head j */
+                    i = Last [j] ;
+                    Last [j] = EMPTY ;
+                }
+
+                /* if separate Hhead array is used: *
+                i = Hhead [hash] ;
+                Hhead [hash] = EMPTY ;
+                */
+
+                ASSERT (i >= EMPTY && i < n) ;
+                AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
+
+                while (i != EMPTY && Next [i] != EMPTY)
+                {
+
+                    /* -----------------------------------------------------
+                     * this bucket has one or more variables following i.
+                     * scan all of them to see if i can absorb any entries
+                     * that follow i in hash bucket.  Scatter i into w.
+                     * ----------------------------------------------------- */
+
+                    ln = Len [i] ;
+                    eln = Elen [i] ;
+                    ASSERT (ln >= 0 && eln >= 0) ;
+                    ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
+                    /* do not flag the first element in the list (me) */
+                    for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
+                    {
+                        ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+                        W [Iw [p]] = wflg ;
+                    }
+
+                    /* ----------------------------------------------------- */
+                    /* scan every other entry j following i in bucket */
+                    /* ----------------------------------------------------- */
+
+                    jlast = i ;
+                    j = Next [i] ;
+                    ASSERT (j >= EMPTY && j < n) ;
+
+                    while (j != EMPTY)
+                    {
+                        /* ------------------------------------------------- */
+                        /* check if j and i have identical nonzero pattern */
+                        /* ------------------------------------------------- */
+
+                        AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
+
+                        /* check if i and j have the same Len and Elen */
+                        ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
+                        ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
+                        ok = (Len [j] == ln) && (Elen [j] == eln) ;
+                        /* skip the first element in the list (me) */
+                        for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
+                        {
+                            ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+                            if (W [Iw [p]] != wflg) ok = 0 ;
+                        }
+                        if (ok)
+                        {
+                            /* --------------------------------------------- */
+                            /* found it!  j can be absorbed into i */
+                            /* --------------------------------------------- */
+
+                            AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
+                            Pe [j] = FLIP (i) ;
+                            /* both Nv [i] and Nv [j] are negated since they */
+                            /* are in Lme, and the absolute values of each */
+                            /* are the number of variables in i and j: */
+                            Nv [i] += Nv [j] ;
+                            Nv [j] = 0 ;
+                            Elen [j] = EMPTY ;
+                            /* delete j from hash bucket */
+                            ASSERT (j != Next [j]) ;
+                            j = Next [j] ;
+                            Next [jlast] = j ;
+
+                        }
+                        else
+                        {
+                            /* j cannot be absorbed into i */
+                            jlast = j ;
+                            ASSERT (j != Next [j]) ;
+                            j = Next [j] ;
+                        }
+                        ASSERT (j >= EMPTY && j < n) ;
+                    }
+
+                    /* -----------------------------------------------------
+                     * no more variables can be absorbed into i
+                     * go to next i in bucket and clear flag array
+                     * ----------------------------------------------------- */
+
+                    wflg++ ;
+                    i = Next [i] ;
+                    ASSERT (i >= EMPTY && i < n) ;
+
+                }
+            }
+        }
+        AMD_DEBUG2 (("detect done\n")) ;
+
+/* ========================================================================= */
+/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
+/* ========================================================================= */
+
+        p = pme1 ;
+        nleft = n - nel ;
+        for (pme = pme1 ; pme <= pme2 ; pme++)
+        {
+            i = Iw [pme] ;
+            ASSERT (i >= 0 && i < n) ;
+            nvi = -Nv [i] ;
+            AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
+            if (nvi > 0)
+            {
+                /* i is a principal variable in Lme */
+                /* restore Nv [i] to signify that i is principal */
+                Nv [i] = nvi ;
+
+                /* --------------------------------------------------------- */
+                /* compute the external degree (add size of current element) */
+                /* --------------------------------------------------------- */
+
+                deg = Degree [i] + degme - nvi ;
+                deg = MIN (deg, nleft - nvi) ;
+                ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
+
+                /* --------------------------------------------------------- */
+                /* place the supervariable at the head of the degree list */
+                /* --------------------------------------------------------- */
+
+                inext = Head [deg] ;
+                ASSERT (inext >= EMPTY && inext < n) ;
+                if (inext != EMPTY) Last [inext] = i ;
+                Next [i] = inext ;
+                Last [i] = EMPTY ;
+                Head [deg] = i ;
+
+                /* --------------------------------------------------------- */
+                /* save the new degree, and find the minimum degree */
+                /* --------------------------------------------------------- */
+
+                mindeg = MIN (mindeg, deg) ;
+                Degree [i] = deg ;
+
+                /* --------------------------------------------------------- */
+                /* place the supervariable in the element pattern */
+                /* --------------------------------------------------------- */
+
+                Iw [p++] = i ;
+
+            }
+        }
+        AMD_DEBUG2 (("restore done\n")) ;
+
+/* ========================================================================= */
+/* FINALIZE THE NEW ELEMENT */
+/* ========================================================================= */
+
+        AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
+        Nv [me] = nvpiv ;
+        /* save the length of the list for the new element me */
+        Len [me] = p - pme1 ;
+        if (Len [me] == 0)
+        {
+            /* there is nothing left of the current pivot element */
+            /* it is a root of the assembly tree */
+            Pe [me] = EMPTY ;
+            W [me] = 0 ;
+        }
+        if (elenme != 0)
+        {
+            /* element was not constructed in place: deallocate part of */
+            /* it since newly nonprincipal variables may have been removed */
+            pfree = p ;
+        }
+
+        /* The new element has nvpiv pivots and the size of the contribution
+         * block for a multifrontal method is degme-by-degme, not including
+         * the "dense" rows/columns.  If the "dense" rows/columns are included,
+         * the frontal matrix is no larger than
+         * (degme+ndense)-by-(degme+ndense).
+         */
+
+        if (Info != (double *) NULL)
+        {
+            f = nvpiv ;
+            r = degme + ndense ;
+            dmax = MAX (dmax, f + r) ;
+
+            /* number of nonzeros in L (excluding the diagonal) */
+            lnzme = f*r + (f-1)*f/2 ;
+            lnz += lnzme ;
+
+            /* number of divide operations for LDL' and for LU */
+            ndiv += lnzme ;
+
+            /* number of multiply-subtract pairs for LU */
+            s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
+            nms_lu += s ;
+
+            /* number of multiply-subtract pairs for LDL' */
+            nms_ldl += (s + lnzme)/2 ;
+        }
+
+#ifndef NDEBUG
+        AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n   ::::\n", nel, n)) ;
+        for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
+        {
+              AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
+        }
+        AMD_DEBUG3 (("\n")) ;
+#endif
+
+    }
+
+/* ========================================================================= */
+/* DONE SELECTING PIVOTS */
+/* ========================================================================= */
+
+    if (Info != (double *) NULL)
+    {
+
+        /* count the work to factorize the ndense-by-ndense submatrix */
+        f = ndense ;
+        dmax = MAX (dmax, (double) ndense) ;
+
+        /* number of nonzeros in L (excluding the diagonal) */
+        lnzme = (f-1)*f/2 ;
+        lnz += lnzme ;
+
+        /* number of divide operations for LDL' and for LU */
+        ndiv += lnzme ;
+
+        /* number of multiply-subtract pairs for LU */
+        s = (f-1)*f*(2*f-1)/6 ;
+        nms_lu += s ;
+
+        /* number of multiply-subtract pairs for LDL' */
+        nms_ldl += (s + lnzme)/2 ;
+
+        /* number of nz's in L (excl. diagonal) */
+        Info [AMD_LNZ] = lnz ;
+
+        /* number of divide ops for LU and LDL' */
+        Info [AMD_NDIV] = ndiv ;
+
+        /* number of multiply-subtract pairs for LDL' */
+        Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
+
+        /* number of multiply-subtract pairs for LU */
+        Info [AMD_NMULTSUBS_LU] = nms_lu ;
+
+        /* number of "dense" rows/columns */
+        Info [AMD_NDENSE] = ndense ;
+
+        /* largest front is dmax-by-dmax */
+        Info [AMD_DMAX] = dmax ;
+
+        /* number of garbage collections in AMD */
+        Info [AMD_NCMPA] = ncmpa ;
+
+        /* successful ordering */
+        Info [AMD_STATUS] = AMD_OK ;
+    }
+
+/* ========================================================================= */
+/* POST-ORDERING */
+/* ========================================================================= */
+
+/* -------------------------------------------------------------------------
+ * Variables at this point:
+ *
+ * Pe: holds the elimination tree.  The parent of j is FLIP (Pe [j]),
+ *      or EMPTY if j is a root.  The tree holds both elements and
+ *      non-principal (unordered) variables absorbed into them.
+ *      Dense variables are non-principal and unordered.
+ *
+ * Elen: holds the size of each element, including the diagonal part.
+ *      FLIP (Elen [e]) > 0 if e is an element.  For unordered
+ *      variables i, Elen [i] is EMPTY.
+ *
+ * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
+ *      For unordered variables i, Nv [i] is zero.
+ *
+ * Contents no longer needed:
+ *      W, Iw, Len, Degree, Head, Next, Last.
+ *
+ * The matrix itself has been destroyed.
+ *
+ * n: the size of the matrix.
+ * No other scalars needed (pfree, iwlen, etc.)
+ * ------------------------------------------------------------------------- */
+
+    /* restore Pe */
+    for (i = 0 ; i < n ; i++)
+    {
+        Pe [i] = FLIP (Pe [i]) ;
+    }
+
+    /* restore Elen, for output information, and for postordering */
+    for (i = 0 ; i < n ; i++)
+    {
+        Elen [i] = FLIP (Elen [i]) ;
+    }
+
+/* Now the parent of j is Pe [j], or EMPTY if j is a root.  Elen [e] > 0
+ * is the size of element e.  Elen [i] is EMPTY for unordered variable i. */
+
+#ifndef NDEBUG
+    AMD_DEBUG2 (("\nTree:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+        AMD_DEBUG2 ((" "ID" parent: "ID"   ", i, Pe [i])) ;
+        ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
+        if (Nv [i] > 0)
+        {
+            /* this is an element */
+            e = i ;
+            AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
+            ASSERT (Elen [e] > 0) ;
+        }
+        AMD_DEBUG2 (("\n")) ;
+    }
+    AMD_DEBUG2 (("\nelements:\n")) ;
+    for (e = 0 ; e < n ; e++)
+    {
+        if (Nv [e] > 0)
+        {
+            AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
+                Elen [e], Nv [e])) ;
+        }
+    }
+    AMD_DEBUG2 (("\nvariables:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+        Int cnt ;
+        if (Nv [i] == 0)
+        {
+            AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
+            j = Pe [i] ;
+            cnt = 0 ;
+            AMD_DEBUG3 (("  j: "ID"\n", j)) ;
+            if (j == EMPTY)
+            {
+                AMD_DEBUG3 (("  i is a dense variable\n")) ;
+            }
+            else
+            {
+                ASSERT (j >= 0 && j < n) ;
+                while (Nv [j] == 0)
+                {
+                    AMD_DEBUG3 (("      j : "ID"\n", j)) ;
+                    j = Pe [j] ;
+                    AMD_DEBUG3 (("      j:: "ID"\n", j)) ;
+                    cnt++ ;
+                    if (cnt > n) break ;
+                }
+                e = j ;
+                AMD_DEBUG3 (("  got to e: "ID"\n", e)) ;
+            }
+        }
+    }
+#endif
+
+/* ========================================================================= */
+/* compress the paths of the variables */
+/* ========================================================================= */
+
+    for (i = 0 ; i < n ; i++)
+    {
+        if (Nv [i] == 0)
+        {
+
+            /* -------------------------------------------------------------
+             * i is an un-ordered row.  Traverse the tree from i until
+             * reaching an element, e.  The element, e, was the principal
+             * supervariable of i and all nodes in the path from i to when e
+             * was selected as pivot.
+             * ------------------------------------------------------------- */
+
+            AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
+            j = Pe [i] ;
+            ASSERT (j >= EMPTY && j < n) ;
+            AMD_DEBUG3 (("      j: "ID"\n", j)) ;
+            if (j == EMPTY)
+            {
+                /* Skip a dense variable.  It has no parent. */
+                AMD_DEBUG3 (("      i is a dense variable\n")) ;
+                continue ;
+            }
+
+            /* while (j is a variable) */
+            while (Nv [j] == 0)
+            {
+                AMD_DEBUG3 (("          j : "ID"\n", j)) ;
+                j = Pe [j] ;
+                AMD_DEBUG3 (("          j:: "ID"\n", j)) ;
+                ASSERT (j >= 0 && j < n) ;
+            }
+            /* got to an element e */
+            e = j ;
+            AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
+
+            /* -------------------------------------------------------------
+             * traverse the path again from i to e, and compress the path
+             * (all nodes point to e).  Path compression allows this code to
+             * compute in O(n) time.
+             * ------------------------------------------------------------- */
+
+            j = i ;
+            /* while (j is a variable) */
+            while (Nv [j] == 0)
+            {
+                jnext = Pe [j] ;
+                AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
+                Pe [j] = e ;
+                j = jnext ;
+                ASSERT (j >= 0 && j < n) ;
+            }
+        }
+    }
+
+/* ========================================================================= */
+/* postorder the assembly tree */
+/* ========================================================================= */
+
+    AMD_postorder (n, Pe, Nv, Elen,
+        W,                      /* output order */
+        Head, Next, Last) ;     /* workspace */
+
+/* ========================================================================= */
+/* compute output permutation and inverse permutation */
+/* ========================================================================= */
+
+    /* W [e] = k means that element e is the kth element in the new
+     * order.  e is in the range 0 to n-1, and k is in the range 0 to
+     * the number of elements.  Use Head for inverse order. */
+
+    for (k = 0 ; k < n ; k++)
+    {
+        Head [k] = EMPTY ;
+        Next [k] = EMPTY ;
+    }
+    for (e = 0 ; e < n ; e++)
+    {
+        k = W [e] ;
+        ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
+        if (k != EMPTY)
+        {
+            ASSERT (k >= 0 && k < n) ;
+            Head [k] = e ;
+        }
+    }
+
+    /* construct output inverse permutation in Next,
+     * and permutation in Last */
+    nel = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+        e = Head [k] ;
+        if (e == EMPTY) break ;
+        ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
+        Next [e] = nel ;
+        nel += Nv [e] ;
+    }
+    ASSERT (nel == n - ndense) ;
+
+    /* order non-principal variables (dense, & those merged into supervar's) */
+    for (i = 0 ; i < n ; i++)
+    {
+        if (Nv [i] == 0)
+        {
+            e = Pe [i] ;
+            ASSERT (e >= EMPTY && e < n) ;
+            if (e != EMPTY)
+            {
+                /* This is an unordered variable that was merged
+                 * into element e via supernode detection or mass
+                 * elimination of i when e became the pivot element.
+                 * Place i in order just before e. */
+                ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
+                Next [i] = Next [e] ;
+                Next [e]++ ;
+            }
+            else
+            {
+                /* This is a dense unordered variable, with no parent.
+                 * Place it last in the output order. */
+                Next [i] = nel++ ;
+            }
+        }
+    }
+    ASSERT (nel == n) ;
+
+    AMD_DEBUG2 (("\n\nPerm:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+        k = Next [i] ;
+        ASSERT (k >= 0 && k < n) ;
+        Last [k] = i ;
+        AMD_DEBUG2 (("   perm ["ID"] = "ID"\n", k, i)) ;
+    }
+}
Index: deps/glpk/src/amd/amd_aat.c
===================================================================
--- deps/glpk/src/amd/amd_aat.c	(revision 9)
+++ deps/glpk/src/amd/amd_aat.c	(revision 9)
@@ -0,0 +1,185 @@
+/* ========================================================================= */
+/* === AMD_aat ============================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_aat:  compute the symmetry of the pattern of A, and count the number of
+ * nonzeros each column of A+A' (excluding the diagonal).  Assumes the input
+ * matrix has no errors, with sorted columns and no duplicates
+ * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
+ * checked).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL size_t AMD_aat   /* returns nz in A+A' */
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Len [ ],        /* Len [j]: length of column j of A+A', excl diagonal*/
+    Int Tp [ ],         /* workspace of size n */
+    double Info [ ]
+)
+{
+    Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
+    double sym ;
+    size_t nzaat ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("AMD AAT") ;
+    for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
+    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+#endif
+
+    if (Info != (double *) NULL)
+    {
+        /* clear the Info array, if it exists */
+        for (i = 0 ; i < AMD_INFO ; i++)
+        {
+            Info [i] = EMPTY ;
+        }
+        Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    for (k = 0 ; k < n ; k++)
+    {
+        Len [k] = 0 ;
+    }
+
+    nzdiag = 0 ;
+    nzboth = 0 ;
+    nz = Ap [n] ;
+
+    for (k = 0 ; k < n ; k++)
+    {
+        p1 = Ap [k] ;
+        p2 = Ap [k+1] ;
+        AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
+
+        /* construct A+A' */
+        for (p = p1 ; p < p2 ; )
+        {
+            /* scan the upper triangular part of A */
+            j = Ai [p] ;
+            if (j < k)
+            {
+                /* entry A (j,k) is in the strictly upper triangular part,
+                 * add both A (j,k) and A (k,j) to the matrix A+A' */
+                Len [j]++ ;
+                Len [k]++ ;
+                AMD_DEBUG3 (("    upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
+                p++ ;
+            }
+            else if (j == k)
+            {
+                /* skip the diagonal */
+                p++ ;
+                nzdiag++ ;
+                break ;
+            }
+            else /* j > k */
+            {
+                /* first entry below the diagonal */
+                break ;
+            }
+            /* scan lower triangular part of A, in column j until reaching
+             * row k.  Start where last scan left off. */
+            ASSERT (Tp [j] != EMPTY) ;
+            ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+            pj2 = Ap [j+1] ;
+            for (pj = Tp [j] ; pj < pj2 ; )
+            {
+                i = Ai [pj] ;
+                if (i < k)
+                {
+                    /* A (i,j) is only in the lower part, not in upper.
+                     * add both A (i,j) and A (j,i) to the matrix A+A' */
+                    Len [i]++ ;
+                    Len [j]++ ;
+                    AMD_DEBUG3 (("    lower ("ID","ID") ("ID","ID")\n",
+                        i,j, j,i)) ;
+                    pj++ ;
+                }
+                else if (i == k)
+                {
+                    /* entry A (k,j) in lower part and A (j,k) in upper */
+                    pj++ ;
+                    nzboth++ ;
+                    break ;
+                }
+                else /* i > k */
+                {
+                    /* consider this entry later, when k advances to i */
+                    break ;
+                }
+            }
+            Tp [j] = pj ;
+        }
+        /* Tp [k] points to the entry just below the diagonal in column k */
+        Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+        for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+        {
+            i = Ai [pj] ;
+            /* A (i,j) is only in the lower part, not in upper.
+             * add both A (i,j) and A (j,i) to the matrix A+A' */
+            Len [i]++ ;
+            Len [j]++ ;
+            AMD_DEBUG3 (("    lower cleanup ("ID","ID") ("ID","ID")\n",
+                i,j, j,i)) ;
+        }
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* compute the symmetry of the nonzero pattern of A */
+    /* --------------------------------------------------------------------- */
+
+    /* Given a matrix A, the symmetry of A is:
+     *  B = tril (spones (A), -1) + triu (spones (A), 1) ;
+     *  sym = nnz (B & B') / nnz (B) ;
+     *  or 1 if nnz (B) is zero.
+     */
+
+    if (nz == nzdiag)
+    {
+        sym = 1 ;
+    }
+    else
+    {
+        sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
+    }
+
+    nzaat = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+        nzaat += Len [k] ;
+    }
+
+    AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
+        (double) nzaat)) ;
+    AMD_DEBUG1 (("   nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
+                nzboth, nz, nzdiag, sym)) ;
+
+    if (Info != (double *) NULL)
+    {
+        Info [AMD_STATUS] = AMD_OK ;
+        Info [AMD_N] = n ;
+        Info [AMD_NZ] = nz ;
+        Info [AMD_SYMMETRY] = sym ;         /* symmetry of pattern of A */
+        Info [AMD_NZDIAG] = nzdiag ;        /* nonzeros on diagonal of A */
+        Info [AMD_NZ_A_PLUS_AT] = nzaat ;   /* nonzeros in A+A' */
+    }
+
+    return (nzaat) ;
+}
Index: deps/glpk/src/amd/amd_control.c
===================================================================
--- deps/glpk/src/amd/amd_control.c	(revision 9)
+++ deps/glpk/src/amd/amd_control.c	(revision 9)
@@ -0,0 +1,64 @@
+/* ========================================================================= */
+/* === AMD_control ========================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Prints the control parameters for AMD.  See amd.h
+ * for details.  If the Control array is not present, the defaults are
+ * printed instead.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_control
+(
+    double Control [ ]
+)
+{
+    double alpha ;
+    Int aggressive ;
+
+    if (Control != (double *) NULL)
+    {
+        alpha = Control [AMD_DENSE] ;
+        aggressive = Control [AMD_AGGRESSIVE] != 0 ;
+    }
+    else
+    {
+        alpha = AMD_DEFAULT_DENSE ;
+        aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+
+    PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n"
+        "    dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION,
+        AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ;
+
+    if (alpha < 0)
+    {
+        PRINTF (("    no rows treated as dense\n")) ;
+    }
+    else
+    {
+        PRINTF ((
+        "    (rows with more than max (%g * sqrt (n), 16) entries are\n"
+        "    considered \"dense\", and placed last in output permutation)\n",
+        alpha)) ;
+    }
+
+    if (aggressive)
+    {
+        PRINTF (("    aggressive absorption:  yes\n")) ;
+    }
+    else
+    {
+        PRINTF (("    aggressive absorption:  no\n")) ;
+    }
+
+    PRINTF (("    size of AMD integer: %d\n\n", sizeof (Int))) ;
+}
Index: deps/glpk/src/amd/amd_defaults.c
===================================================================
--- deps/glpk/src/amd/amd_defaults.c	(revision 9)
+++ deps/glpk/src/amd/amd_defaults.c	(revision 9)
@@ -0,0 +1,38 @@
+/* ========================================================================= */
+/* === AMD_defaults ======================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Sets default control parameters for AMD.  See amd.h
+ * for details.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD defaults ======================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_defaults
+(
+    double Control [ ]
+)
+{
+    Int i ;
+
+    if (Control != (double *) NULL)
+    {
+        for (i = 0 ; i < AMD_CONTROL ; i++)
+        {
+            Control [i] = 0 ;
+        }
+        Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
+        Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
+    }
+}
Index: deps/glpk/src/amd/amd_dump.c
===================================================================
--- deps/glpk/src/amd/amd_dump.c	(revision 9)
+++ deps/glpk/src/amd/amd_dump.c	(revision 9)
@@ -0,0 +1,180 @@
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Debugging routines for AMD.  Not used if NDEBUG is not defined at compile-
+ * time (the default).  See comments in amd_internal.h on how to enable
+ * debugging.  Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+#ifndef NDEBUG
+
+/* This global variable is present only when debugging */
+GLOBAL Int AMD_debug = -999 ;           /* default is no debug printing */
+
+/* ========================================================================= */
+/* === AMD_debug_init ====================================================== */
+/* ========================================================================= */
+
+/* Sets the debug print level, by reading the file debug.amd (if it exists) */
+
+GLOBAL void AMD_debug_init ( char *s )
+{
+    FILE *f ;
+    f = fopen ("debug.amd", "r") ;
+    if (f == (FILE *) NULL)
+    {
+        AMD_debug = -999 ;
+    }
+    else
+    {
+        fscanf (f, ID, &AMD_debug) ;
+        fclose (f) ;
+    }
+    if (AMD_debug >= 0)
+    {
+        printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ;
+    }
+}
+
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* Dump AMD's data structure, except for the hash buckets.  This routine
+ * cannot be called when the hash buckets are non-empty.
+ */
+
+GLOBAL void AMD_dump (
+    Int n,          /* A is n-by-n */
+    Int Pe [ ],     /* pe [0..n-1]: index in iw of start of row i */
+    Int Iw [ ],     /* workspace of size iwlen, iwlen [0..pfree-1]
+                     * holds the matrix on input */
+    Int Len [ ],    /* len [0..n-1]: length for row i */
+    Int iwlen,      /* length of iw */
+    Int pfree,      /* iw [pfree ... iwlen-1] is empty on input */
+    Int Nv [ ],     /* nv [0..n-1] */
+    Int Next [ ],   /* next [0..n-1] */
+    Int Last [ ],   /* last [0..n-1] */
+    Int Head [ ],   /* head [0..n-1] */
+    Int Elen [ ],   /* size n */
+    Int Degree [ ], /* size n */
+    Int W [ ],      /* size n */
+    Int nel
+)
+{
+    Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
+
+    if (AMD_debug < 0) return ;
+    ASSERT (pfree <= iwlen) ;
+    AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ;
+    for (i = 0 ; i < n ; i++)
+    {
+        pe = Pe [i] ;
+        elen = Elen [i] ;
+        nv = Nv [i] ;
+        len = Len [i] ;
+        w = W [i] ;
+
+        if (elen >= EMPTY)
+        {
+            if (nv == 0)
+            {
+                AMD_DEBUG3 (("\nI "ID": nonprincipal:    ", i)) ;
+                ASSERT (elen == EMPTY) ;
+                if (pe == EMPTY)
+                {
+                    AMD_DEBUG3 ((" dense node\n")) ;
+                    ASSERT (w == 1) ;
+                }
+                else
+                {
+                    ASSERT (pe < EMPTY) ;
+                    AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
+                }
+            }
+            else
+            {
+                AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
+                AMD_DEBUG3 (("   nv(i): "ID"  Flag: %d\n", nv, (nv < 0))) ;
+                ASSERT (elen >= 0) ;
+                ASSERT (nv > 0 && pe >= 0) ;
+                p = pe ;
+                AMD_DEBUG3 (("   e/s: ")) ;
+                if (elen == 0) AMD_DEBUG3 ((" : ")) ;
+                ASSERT (pe + len <= pfree) ;
+                for (k = 0 ; k < len ; k++)
+                {
+                    j = Iw [p] ;
+                    AMD_DEBUG3 (("  "ID"", j)) ;
+                    ASSERT (j >= 0 && j < n) ;
+                    if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
+                    p++ ;
+                }
+                AMD_DEBUG3 (("\n")) ;
+            }
+        }
+        else
+        {
+            e = i ;
+            if (w == 0)
+            {
+                AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
+                ASSERT (nv > 0 && pe < 0) ;
+                AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
+            }
+            else
+            {
+                AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
+                ASSERT (nv > 0 && pe >= 0) ;
+                p = pe ;
+                AMD_DEBUG3 ((" : ")) ;
+                ASSERT (pe + len <= pfree) ;
+                for (k = 0 ; k < len ; k++)
+                {
+                    j = Iw [p] ;
+                    AMD_DEBUG3 (("  "ID"", j)) ;
+                    ASSERT (j >= 0 && j < n) ;
+                    p++ ;
+                }
+                AMD_DEBUG3 (("\n")) ;
+            }
+        }
+    }
+
+    /* this routine cannot be called when the hash buckets are non-empty */
+    AMD_DEBUG3 (("\nDegree lists:\n")) ;
+    if (nel >= 0)
+    {
+        cnt = 0 ;
+        for (deg = 0 ; deg < n ; deg++)
+        {
+            if (Head [deg] == EMPTY) continue ;
+            ilast = EMPTY ;
+            AMD_DEBUG3 ((ID": \n", deg)) ;
+            for (i = Head [deg] ; i != EMPTY ; i = Next [i])
+            {
+                AMD_DEBUG3 (("   "ID" : next "ID" last "ID" deg "ID"\n",
+                    i, Next [i], Last [i], Degree [i])) ;
+                ASSERT (i >= 0 && i < n && ilast == Last [i] &&
+                    deg == Degree [i]) ;
+                cnt += Nv [i] ;
+                ilast = i ;
+            }
+            AMD_DEBUG3 (("\n")) ;
+        }
+        ASSERT (cnt == n - nel) ;
+    }
+
+}
+
+#endif
Index: deps/glpk/src/amd/amd_info.c
===================================================================
--- deps/glpk/src/amd/amd_info.c	(revision 9)
+++ deps/glpk/src/amd/amd_info.c	(revision 9)
@@ -0,0 +1,120 @@
+/* ========================================================================= */
+/* === AMD_info ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Prints the output statistics for AMD.  See amd.h
+ * for details.  If the Info array is not present, nothing is printed.
+ */
+
+#include "amd_internal.h"
+
+#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
+
+GLOBAL void AMD_info
+(
+    double Info [ ]
+)
+{
+    double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
+
+    PRINTF (("\nAMD version %d.%d.%d, %s, results:\n",
+        AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ;
+
+    if (!Info)
+    {
+        return ;
+    }
+
+    n = Info [AMD_N] ;
+    ndiv = Info [AMD_NDIV] ;
+    nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
+    nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
+    lnz = Info [AMD_LNZ] ;
+    lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
+
+    /* AMD return status */
+    PRINTF (("    status: ")) ;
+    if (Info [AMD_STATUS] == AMD_OK)
+    {
+        PRINTF (("OK\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
+    {
+        PRINTF (("out of memory\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_INVALID)
+    {
+        PRINTF (("invalid matrix\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED)
+    {
+        PRINTF (("OK, but jumbled\n")) ;
+    }
+    else
+    {
+        PRINTF (("unknown\n")) ;
+    }
+
+    /* statistics about the input matrix */
+    PRI ("    n, dimension of A:                                  %.20g\n", n);
+    PRI ("    nz, number of nonzeros in A:                        %.20g\n",
+        Info [AMD_NZ]) ;
+    PRI ("    symmetry of A:                                      %.4f\n",
+        Info [AMD_SYMMETRY]) ;
+    PRI ("    number of nonzeros on diagonal:                     %.20g\n",
+        Info [AMD_NZDIAG]) ;
+    PRI ("    nonzeros in pattern of A+A' (excl. diagonal):       %.20g\n",
+        Info [AMD_NZ_A_PLUS_AT]) ;
+    PRI ("    # dense rows/columns of A+A':                       %.20g\n",
+        Info [AMD_NDENSE]) ;
+
+    /* statistics about AMD's behavior  */
+    PRI ("    memory used, in bytes:                              %.20g\n",
+        Info [AMD_MEMORY]) ;
+    PRI ("    # of memory compactions:                            %.20g\n",
+        Info [AMD_NCMPA]) ;
+
+    /* statistics about the ordering quality */
+    PRINTF (("\n"
+        "    The following approximate statistics are for a subsequent\n"
+        "    factorization of A(P,P) + A(P,P)'.  They are slight upper\n"
+        "    bounds if there are no dense rows/columns in A+A', and become\n"
+        "    looser if dense rows/columns exist.\n\n")) ;
+
+    PRI ("    nonzeros in L (excluding diagonal):                 %.20g\n",
+        lnz) ;
+    PRI ("    nonzeros in L (including diagonal):                 %.20g\n",
+        lnzd) ;
+    PRI ("    # divide operations for LDL' or LU:                 %.20g\n",
+        ndiv) ;
+    PRI ("    # multiply-subtract operations for LDL':            %.20g\n",
+        nmultsubs_ldl) ;
+    PRI ("    # multiply-subtract operations for LU:              %.20g\n",
+        nmultsubs_lu) ;
+    PRI ("    max nz. in any column of L (incl. diagonal):        %.20g\n",
+        Info [AMD_DMAX]) ;
+
+    /* total flop counts for various factorizations */
+
+    if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
+    {
+        PRINTF (("\n"
+        "    chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
+        "    LDL' flop count for real A:                         %.20g\n"
+        "    LDL' flop count for complex A:                      %.20g\n"
+        "    LU flop count for real A (with no pivoting):        %.20g\n"
+        "    LU flop count for complex A (with no pivoting):     %.20g\n\n",
+        n + ndiv + 2*nmultsubs_ldl,
+            ndiv + 2*nmultsubs_ldl,
+          9*ndiv + 8*nmultsubs_ldl,
+            ndiv + 2*nmultsubs_lu,
+          9*ndiv + 8*nmultsubs_lu)) ;
+    }
+}
Index: deps/glpk/src/amd/amd_internal.h
===================================================================
--- deps/glpk/src/amd/amd_internal.h	(revision 9)
+++ deps/glpk/src/amd/amd_internal.h	(revision 9)
@@ -0,0 +1,113 @@
+/* amd_internal.h */
+
+/* Written by Andrew Makhorin <mao@gnu.org>. */
+
+#ifndef AMD_INTERNAL_H
+#define AMD_INTERNAL_H
+
+/* AMD will be exceedingly slow when running in debug mode. */
+#if 1
+#define NDEBUG
+#endif
+
+#include "amd.h"
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define SIZE_T_MAX ((size_t)(-1))
+
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define IMPLIES(p, q) (!(p) || (q))
+
+#define GLOBAL
+
+#define AMD_order amd_order
+#define AMD_defaults amd_defaults
+#define AMD_control amd_control
+#define AMD_info amd_info
+#define AMD_1 amd_1
+#define AMD_2 amd_2
+#define AMD_valid amd_valid
+#define AMD_aat amd_aat
+#define AMD_postorder amd_postorder
+#define AMD_post_tree amd_post_tree
+#define AMD_dump amd_dump
+#define AMD_debug amd_debug
+#define AMD_debug_init amd_debug_init
+#define AMD_preprocess amd_preprocess
+
+#define amd_malloc xmalloc
+#if 0 /* 24/V-2009 */
+#define amd_free xfree
+#else
+#define amd_free(ptr) { if ((ptr) != NULL) xfree(ptr); } 
+#endif
+#define amd_printf xprintf
+
+#define PRINTF(params) { amd_printf params; }
+
+#ifndef NDEBUG
+#define ASSERT(expr) xassert(expr)
+#define AMD_DEBUG0(params) { PRINTF(params); }
+#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF(params); }
+#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF(params); }
+#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF(params); }
+#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF(params); }
+#else
+#define ASSERT(expression)
+#define AMD_DEBUG0(params)
+#define AMD_DEBUG1(params)
+#define AMD_DEBUG2(params)
+#define AMD_DEBUG3(params)
+#define AMD_DEBUG4(params)
+#endif
+
+#define amd_aat _glp_amd_aat
+size_t AMD_aat(Int n, const Int Ap[], const Int Ai[], Int Len[],
+      Int Tp[], double Info[]);
+
+#define amd_1 _glp_amd_1
+void AMD_1(Int n, const Int Ap[], const Int Ai[], Int P[], Int Pinv[],
+      Int Len[], Int slen, Int S[], double Control[], double Info[]);
+
+#define amd_postorder _glp_amd_postorder
+void AMD_postorder(Int nn, Int Parent[], Int Npiv[], Int Fsize[],
+      Int Order[], Int Child[], Int Sibling[], Int Stack[]);
+
+#define amd_post_tree _glp_amd_post_tree
+#ifndef NDEBUG
+Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
+      Int Order[], Int Stack[], Int nn);
+#else
+Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[],
+      Int Order[], Int Stack[]);
+#endif
+
+#define amd_preprocess _glp_amd_preprocess
+void AMD_preprocess(Int n, const Int Ap[], const Int Ai[], Int Rp[],
+      Int Ri[], Int W[], Int Flag[]);
+
+#define amd_debug _glp_amd_debug
+extern Int AMD_debug;
+
+#define amd_debug_init _glp_amd_debug_init
+void AMD_debug_init(char *s);
+
+#define amd_dump _glp_amd_dump
+void AMD_dump(Int n, Int Pe[], Int Iw[], Int Len[], Int iwlen,
+      Int pfree, Int Nv[], Int Next[], Int Last[], Int Head[],
+      Int Elen[], Int Degree[], Int W[], Int nel);
+
+#endif
+
+/* eof */
Index: deps/glpk/src/amd/amd_order.c
===================================================================
--- deps/glpk/src/amd/amd_order.c	(revision 9)
+++ deps/glpk/src/amd/amd_order.c	(revision 9)
@@ -0,0 +1,200 @@
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable AMD minimum degree ordering routine.  See amd.h for
+ * documentation.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+GLOBAL Int AMD_order
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int P [ ],
+    double Control [ ],
+    double Info [ ]
+)
+{
+    Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
+    size_t nzaat, slen ;
+    double mem = 0 ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("amd") ;
+#endif
+
+    /* clear the Info array, if it exists */
+    info = Info != (double *) NULL ;
+    if (info)
+    {
+        for (i = 0 ; i < AMD_INFO ; i++)
+        {
+            Info [i] = EMPTY ;
+        }
+        Info [AMD_N] = n ;
+        Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    /* make sure inputs exist and n is >= 0 */
+    if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
+    {
+        if (info) Info [AMD_STATUS] = AMD_INVALID ;
+        return (AMD_INVALID) ;      /* arguments are invalid */
+    }
+
+    if (n == 0)
+    {
+        return (AMD_OK) ;           /* n is 0 so there's nothing to do */
+    }
+
+    nz = Ap [n] ;
+    if (info)
+    {
+        Info [AMD_NZ] = nz ;
+    }
+    if (nz < 0)
+    {
+        if (info) Info [AMD_STATUS] = AMD_INVALID ;
+        return (AMD_INVALID) ;
+    }
+
+    /* check if n or nz will cause size_t overflow */
+    if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
+     || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
+    {
+        if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+        return (AMD_OUT_OF_MEMORY) ;        /* problem too large */
+    }
+
+    /* check the input matrix:  AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
+    status = AMD_valid (n, n, Ap, Ai) ;
+
+    if (status == AMD_INVALID)
+    {
+        if (info) Info [AMD_STATUS] = AMD_INVALID ;
+        return (AMD_INVALID) ;      /* matrix is invalid */
+    }
+
+    /* allocate two size-n integer workspaces */
+    Len = amd_malloc (n * sizeof (Int)) ;
+    Pinv = amd_malloc (n * sizeof (Int)) ;
+    mem += n ;
+    mem += n ;
+    if (!Len || !Pinv)
+    {
+        /* :: out of memory :: */
+        amd_free (Len) ;
+        amd_free (Pinv) ;
+        if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+        return (AMD_OUT_OF_MEMORY) ;
+    }
+
+    if (status == AMD_OK_BUT_JUMBLED)
+    {
+        /* sort the input matrix and remove duplicate entries */
+        AMD_DEBUG1 (("Matrix is jumbled\n")) ;
+        Rp = amd_malloc ((n+1) * sizeof (Int)) ;
+        Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
+        mem += (n+1) ;
+        mem += MAX (nz,1) ;
+        if (!Rp || !Ri)
+        {
+            /* :: out of memory :: */
+            amd_free (Rp) ;
+            amd_free (Ri) ;
+            amd_free (Len) ;
+            amd_free (Pinv) ;
+            if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+            return (AMD_OUT_OF_MEMORY) ;
+        }
+        /* use Len and Pinv as workspace to create R = A' */
+        AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
+        Cp = Rp ;
+        Ci = Ri ;
+    }
+    else
+    {
+        /* order the input matrix as-is.  No need to compute R = A' first */
+        Rp = NULL ;
+        Ri = NULL ;
+        Cp = (Int *) Ap ;
+        Ci = (Int *) Ai ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* determine the symmetry and count off-diagonal nonzeros in A+A' */
+    /* --------------------------------------------------------------------- */
+
+    nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
+    AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
+    ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
+
+    /* --------------------------------------------------------------------- */
+    /* allocate workspace for matrix, elbow room, and 6 size-n vectors */
+    /* --------------------------------------------------------------------- */
+
+    S = NULL ;
+    slen = nzaat ;                      /* space for matrix */
+    ok = ((slen + nzaat/5) >= slen) ;   /* check for size_t overflow */
+    slen += nzaat/5 ;                   /* add elbow room */
+    for (i = 0 ; ok && i < 7 ; i++)
+    {
+        ok = ((slen + n) > slen) ;      /* check for size_t overflow */
+        slen += n ;                     /* size-n elbow room, 6 size-n work */
+    }
+    mem += slen ;
+    ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
+    ok = ok && (slen < Int_MAX) ;       /* S[i] for Int i must be OK */
+    if (ok)
+    {
+        S = amd_malloc (slen * sizeof (Int)) ;
+    }
+    AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
+    if (!S)
+    {
+        /* :: out of memory :: (or problem too large) */
+        amd_free (Rp) ;
+        amd_free (Ri) ;
+        amd_free (Len) ;
+        amd_free (Pinv) ;
+        if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+        return (AMD_OUT_OF_MEMORY) ;
+    }
+    if (info)
+    {
+        /* memory usage, in bytes. */
+        Info [AMD_MEMORY] = mem * sizeof (Int) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
+
+    /* --------------------------------------------------------------------- */
+    /* free the workspace */
+    /* --------------------------------------------------------------------- */
+
+    amd_free (Rp) ;
+    amd_free (Ri) ;
+    amd_free (Len) ;
+    amd_free (Pinv) ;
+    amd_free (S) ;
+    if (info) Info [AMD_STATUS] = status ;
+    return (status) ;       /* successful ordering */
+}
Index: deps/glpk/src/amd/amd_post_tree.c
===================================================================
--- deps/glpk/src/amd/amd_post_tree.c	(revision 9)
+++ deps/glpk/src/amd/amd_post_tree.c	(revision 9)
@@ -0,0 +1,121 @@
+/* ========================================================================= */
+/* === AMD_post_tree ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Post-ordering of a supernodal elimination tree.  */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_post_tree
+(
+    Int root,                   /* root of the tree */
+    Int k,                      /* start numbering at k */
+    Int Child [ ],              /* input argument of size nn, undefined on
+                                 * output.  Child [i] is the head of a link
+                                 * list of all nodes that are children of node
+                                 * i in the tree. */
+    const Int Sibling [ ],      /* input argument of size nn, not modified.
+                                 * If f is a node in the link list of the
+                                 * children of node i, then Sibling [f] is the
+                                 * next child of node i.
+                                 */
+    Int Order [ ],              /* output order, of size nn.  Order [i] = k
+                                 * if node i is the kth node of the reordered
+                                 * tree. */
+    Int Stack [ ]               /* workspace of size nn */
+#ifndef NDEBUG
+    , Int nn                    /* nodes are in the range 0..nn-1. */
+#endif
+)
+{
+    Int f, head, h, i ;
+
+#if 0
+    /* --------------------------------------------------------------------- */
+    /* recursive version (Stack [ ] is not used): */
+    /* --------------------------------------------------------------------- */
+
+    /* this is simple, but can caouse stack overflow if nn is large */
+    i = root ;
+    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+    {
+        k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
+    }
+    Order [i] = k++ ;
+    return (k) ;
+#endif
+
+    /* --------------------------------------------------------------------- */
+    /* non-recursive version, using an explicit stack */
+    /* --------------------------------------------------------------------- */
+
+    /* push root on the stack */
+    head = 0 ;
+    Stack [0] = root ;
+
+    while (head >= 0)
+    {
+        /* get head of stack */
+        ASSERT (head < nn) ;
+        i = Stack [head] ;
+        AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
+        ASSERT (i >= 0 && i < nn) ;
+
+        if (Child [i] != EMPTY)
+        {
+            /* the children of i are not yet ordered */
+            /* push each child onto the stack in reverse order */
+            /* so that small ones at the head of the list get popped first */
+            /* and the biggest one at the end of the list gets popped last */
+            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+            {
+                head++ ;
+                ASSERT (head < nn) ;
+                ASSERT (f >= 0 && f < nn) ;
+            }
+            h = head ;
+            ASSERT (head < nn) ;
+            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+            {
+                ASSERT (h > 0) ;
+                Stack [h--] = f ;
+                AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
+                ASSERT (f >= 0 && f < nn) ;
+            }
+            ASSERT (Stack [h] == i) ;
+
+            /* delete child list so that i gets ordered next time we see it */
+            Child [i] = EMPTY ;
+        }
+        else
+        {
+            /* the children of i (if there were any) are already ordered */
+            /* remove i from the stack and order it.  Front i is kth front */
+            head-- ;
+            AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
+            Order [i] = k++ ;
+            ASSERT (k <= nn) ;
+        }
+
+#ifndef NDEBUG
+        AMD_DEBUG1 (("\nStack:")) ;
+        for (h = head ; h >= 0 ; h--)
+        {
+            Int j = Stack [h] ;
+            AMD_DEBUG1 ((" "ID, j)) ;
+            ASSERT (j >= 0 && j < nn) ;
+        }
+        AMD_DEBUG1 (("\n\n")) ;
+        ASSERT (head < nn) ;
+#endif
+
+    }
+    return (k) ;
+}
Index: deps/glpk/src/amd/amd_postorder.c
===================================================================
--- deps/glpk/src/amd/amd_postorder.c	(revision 9)
+++ deps/glpk/src/amd/amd_postorder.c	(revision 9)
@@ -0,0 +1,207 @@
+/* ========================================================================= */
+/* === AMD_postorder ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Perform a postordering (via depth-first search) of an assembly tree. */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_postorder
+(
+    /* inputs, not modified on output: */
+    Int nn,             /* nodes are in the range 0..nn-1 */
+    Int Parent [ ],     /* Parent [j] is the parent of j, or EMPTY if root */
+    Int Nv [ ],         /* Nv [j] > 0 number of pivots represented by node j,
+                         * or zero if j is not a node. */
+    Int Fsize [ ],      /* Fsize [j]: size of node j */
+
+    /* output, not defined on input: */
+    Int Order [ ],      /* output post-order */
+
+    /* workspaces of size nn: */
+    Int Child [ ],
+    Int Sibling [ ],
+    Int Stack [ ]
+)
+{
+    Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
+
+    for (j = 0 ; j < nn ; j++)
+    {
+        Child [j] = EMPTY ;
+        Sibling [j] = EMPTY ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* place the children in link lists - bigger elements tend to be last */
+    /* --------------------------------------------------------------------- */
+
+    for (j = nn-1 ; j >= 0 ; j--)
+    {
+        if (Nv [j] > 0)
+        {
+            /* this is an element */
+            parent = Parent [j] ;
+            if (parent != EMPTY)
+            {
+                /* place the element in link list of the children its parent */
+                /* bigger elements will tend to be at the end of the list */
+                Sibling [j] = Child [parent] ;
+                Child [parent] = j ;
+            }
+        }
+    }
+
+#ifndef NDEBUG
+    {
+        Int nels, ff, nchild ;
+        AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
+        nels = 0 ;
+        for (j = 0 ; j < nn ; j++)
+        {
+            if (Nv [j] > 0)
+            {
+                AMD_DEBUG1 (( ""ID" :  nels "ID" npiv "ID" size "ID
+                    " parent "ID" maxfr "ID"\n", j, nels,
+                    Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
+                /* this is an element */
+                /* dump the link list of children */
+                nchild = 0 ;
+                AMD_DEBUG1 (("    Children: ")) ;
+                for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
+                {
+                    AMD_DEBUG1 ((ID" ", ff)) ;
+                    ASSERT (Parent [ff] == j) ;
+                    nchild++ ;
+                    ASSERT (nchild < nn) ;
+                }
+                AMD_DEBUG1 (("\n")) ;
+                parent = Parent [j] ;
+                if (parent != EMPTY)
+                {
+                    ASSERT (Nv [parent] > 0) ;
+                }
+                nels++ ;
+            }
+        }
+    }
+    AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
+                 "the biggest child last in each list:\n")) ;
+#endif
+
+    /* --------------------------------------------------------------------- */
+    /* place the largest child last in the list of children for each node */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nn ; i++)
+    {
+        if (Nv [i] > 0 && Child [i] != EMPTY)
+        {
+
+#ifndef NDEBUG
+            Int nchild ;
+            AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
+            nchild = 0 ;
+            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+            {
+                ASSERT (f >= 0 && f < nn) ;
+                AMD_DEBUG1 (("      f: "ID"  size: "ID"\n", f, Fsize [f])) ;
+                nchild++ ;
+                ASSERT (nchild <= nn) ;
+            }
+#endif
+
+            /* find the biggest element in the child list */
+            fprev = EMPTY ;
+            maxfrsize = EMPTY ;
+            bigfprev = EMPTY ;
+            bigf = EMPTY ;
+            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+            {
+                ASSERT (f >= 0 && f < nn) ;
+                frsize = Fsize [f] ;
+                if (frsize >= maxfrsize)
+                {
+                    /* this is the biggest seen so far */
+                    maxfrsize = frsize ;
+                    bigfprev = fprev ;
+                    bigf = f ;
+                }
+                fprev = f ;
+            }
+            ASSERT (bigf != EMPTY) ;
+
+            fnext = Sibling [bigf] ;
+
+            AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
+                " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
+
+            if (fnext != EMPTY)
+            {
+                /* if fnext is EMPTY then bigf is already at the end of list */
+
+                if (bigfprev == EMPTY)
+                {
+                    /* delete bigf from the element of the list */
+                    Child [i] = fnext ;
+                }
+                else
+                {
+                    /* delete bigf from the middle of the list */
+                    Sibling [bigfprev] = fnext ;
+                }
+
+                /* put bigf at the end of the list */
+                Sibling [bigf] = EMPTY ;
+                ASSERT (Child [i] != EMPTY) ;
+                ASSERT (fprev != bigf) ;
+                ASSERT (fprev != EMPTY) ;
+                Sibling [fprev] = bigf ;
+            }
+
+#ifndef NDEBUG
+            AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
+            for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+            {
+                ASSERT (f >= 0 && f < nn) ;
+                AMD_DEBUG1 (("        "ID"  "ID"\n", f, Fsize [f])) ;
+                ASSERT (Nv [f] > 0) ;
+                nchild-- ;
+            }
+            ASSERT (nchild == 0) ;
+#endif
+
+        }
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* postorder the assembly tree */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nn ; i++)
+    {
+        Order [i] = EMPTY ;
+    }
+
+    k = 0 ;
+
+    for (i = 0 ; i < nn ; i++)
+    {
+        if (Parent [i] == EMPTY && Nv [i] > 0)
+        {
+            AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
+            k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
+#ifndef NDEBUG
+                , nn
+#endif
+                ) ;
+        }
+    }
+}
Index: deps/glpk/src/amd/amd_preprocess.c
===================================================================
--- deps/glpk/src/amd/amd_preprocess.c	(revision 9)
+++ deps/glpk/src/amd/amd_preprocess.c	(revision 9)
@@ -0,0 +1,119 @@
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
+ * a column-form matrix A, to obtain the matrix R.  The input matrix can have
+ * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be
+ * AMD_INVALID).
+ *
+ * This input condition is NOT checked.  This routine is not user-callable.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* AMD_preprocess does not check its input for errors or allocate workspace.
+ * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold.
+ */
+
+GLOBAL void AMD_preprocess
+(
+    Int n,              /* input matrix: A is n-by-n */
+    const Int Ap [ ],   /* size n+1 */
+    const Int Ai [ ],   /* size nz = Ap [n] */
+
+    /* output matrix R: */
+    Int Rp [ ],         /* size n+1 */
+    Int Ri [ ],         /* size nz (or less, if duplicates present) */
+
+    Int W [ ],          /* workspace of size n */
+    Int Flag [ ]        /* workspace of size n */
+)
+{
+
+    /* --------------------------------------------------------------------- */
+    /* local variables */
+    /* --------------------------------------------------------------------- */
+
+    Int i, j, p, p2 ;
+
+    ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ;
+
+    /* --------------------------------------------------------------------- */
+    /* count the entries in each row of A (excluding duplicates) */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n ; i++)
+    {
+        W [i] = 0 ;             /* # of nonzeros in row i (excl duplicates) */
+        Flag [i] = EMPTY ;      /* Flag [i] = j if i appears in column j */
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+        p2 = Ap [j+1] ;
+        for (p = Ap [j] ; p < p2 ; p++)
+        {
+            i = Ai [p] ;
+            if (Flag [i] != j)
+            {
+                /* row index i has not yet appeared in column j */
+                W [i]++ ;           /* one more entry in row i */
+                Flag [i] = j ;      /* flag row index i as appearing in col j*/
+            }
+        }
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* compute the row pointers for R */
+    /* --------------------------------------------------------------------- */
+
+    Rp [0] = 0 ;
+    for (i = 0 ; i < n ; i++)
+    {
+        Rp [i+1] = Rp [i] + W [i] ;
+    }
+    for (i = 0 ; i < n ; i++)
+    {
+        W [i] = Rp [i] ;
+        Flag [i] = EMPTY ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* construct the row form matrix R */
+    /* --------------------------------------------------------------------- */
+
+    /* R = row form of pattern of A */
+    for (j = 0 ; j < n ; j++)
+    {
+        p2 = Ap [j+1] ;
+        for (p = Ap [j] ; p < p2 ; p++)
+        {
+            i = Ai [p] ;
+            if (Flag [i] != j)
+            {
+                /* row index i has not yet appeared in column j */
+                Ri [W [i]++] = j ;  /* put col j in row i */
+                Flag [i] = j ;      /* flag row index i as appearing in col j*/
+            }
+        }
+    }
+
+#ifndef NDEBUG
+    ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ;
+    for (j = 0 ; j < n ; j++)
+    {
+        ASSERT (W [j] == Rp [j+1]) ;
+    }
+#endif
+}
Index: deps/glpk/src/amd/amd_valid.c
===================================================================
--- deps/glpk/src/amd/amd_valid.c	(revision 9)
+++ deps/glpk/src/amd/amd_valid.c	(revision 9)
@@ -0,0 +1,93 @@
+/* ========================================================================= */
+/* === AMD_valid =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
+/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
+/* ------------------------------------------------------------------------- */
+
+/* Check if a column-form matrix is valid or not.  The matrix A is
+ * n_row-by-n_col.  The row indices of entries in column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1].  Required conditions are:
+ *
+ *      n_row >= 0
+ *      n_col >= 0
+ *      nz = Ap [n_col] >= 0        number of entries in the matrix
+ *      Ap [0] == 0
+ *      Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
+ *      Ai [0 ... nz-1] must be in the range 0 to n_row-1.
+ *
+ * If any of the above conditions hold, AMD_INVALID is returned.  If the
+ * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning,
+ * not an error):
+ *
+ *      row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending
+ *          order, and/or duplicate entries exist.
+ *
+ * Otherwise, AMD_OK is returned.
+ *
+ * In v1.2 and earlier, this function returned TRUE if the matrix was valid
+ * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or
+ * AMD_OK_BUT_JUMBLED).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_valid
+(
+    /* inputs, not modified on output: */
+    Int n_row,          /* A is n_row-by-n_col */
+    Int n_col,
+    const Int Ap [ ],   /* column pointers of A, of size n_col+1 */
+    const Int Ai [ ]    /* row indices of A, of size nz = Ap [n_col] */
+)
+{
+    Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ;
+
+    if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL)
+    {
+        return (AMD_INVALID) ;
+    }
+    nz = Ap [n_col] ;
+    if (Ap [0] != 0 || nz < 0)
+    {
+        /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+        AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+        return (AMD_INVALID) ;
+    }
+    for (j = 0 ; j < n_col ; j++)
+    {
+        p1 = Ap [j] ;
+        p2 = Ap [j+1] ;
+        AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
+        if (p1 > p2)
+        {
+            /* column pointers must be ascending */
+            AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+            return (AMD_INVALID) ;
+        }
+        ilast = EMPTY ;
+        for (p = p1 ; p < p2 ; p++)
+        {
+            i = Ai [p] ;
+            AMD_DEBUG3 (("row: "ID"\n", i)) ;
+            if (i < 0 || i >= n_row)
+            {
+                /* row index out of range */
+                AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
+                return (AMD_INVALID) ;
+            }
+            if (i <= ilast)
+            {
+                /* row index unsorted, or duplicate entry present */
+                AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i));
+                result = AMD_OK_BUT_JUMBLED ;
+            }
+            ilast = i ;
+        }
+    }
+    return (result) ;
+}
Index: deps/glpk/src/colamd/COPYING
===================================================================
--- deps/glpk/src/colamd/COPYING	(revision 9)
+++ deps/glpk/src/colamd/COPYING	(revision 9)
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
Index: deps/glpk/src/colamd/README
===================================================================
--- deps/glpk/src/colamd/README	(revision 9)
+++ deps/glpk/src/colamd/README	(revision 9)
@@ -0,0 +1,98 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+      are used with GLPK.
+
+      The original code was modified according to GLPK requirements by
+      Andrew Makhorin <mao@gnu.org>.
+************************************************************************
+COLAMD/SYMAMD Version 2.7, Copyright (C) 1998-2007, Timothy A. Davis,
+All Rights Reserved.
+
+Description:
+
+   colamd:  an approximate minimum degree column ordering algorithm,
+            for LU factorization of symmetric or unsymmetric matrices,
+            QR factorization, least squares, interior point methods for
+            linear programming problems, and other related problems.
+
+   symamd:  an approximate minimum degree ordering algorithm for
+            Cholesky factorization of symmetric matrices.
+
+Purpose:
+
+   Colamd computes a permutation Q such that the Cholesky factorization
+   of (AQ)'(AQ) has less fill-in and requires fewer floating point
+   operations than A'A.  This also provides a good ordering for sparse
+   partial pivoting methods, P(AQ) = LU, where Q is computed prior to
+   numerical factorization, and P is computed during numerical
+   factorization via conventional partial pivoting with row
+   interchanges.  Colamd is the column ordering method used in SuperLU,
+   part of the ScaLAPACK library.  It is also available as built-in
+   function in MATLAB Version 6, available from MathWorks, Inc.
+   (http://www.mathworks.com).  This routine can be used in place of
+   colmmd in MATLAB.
+
+   Symamd computes a permutation P of a symmetric matrix A such that
+   the Cholesky factorization of PAP' has less fill-in and requires
+   fewer floating point operations than A.  Symamd constructs a matrix
+   M such that M'M has the same nonzero pattern of A, and then orders
+   the columns of M using colmmd.  The column ordering of M is then
+   returned as the row and column ordering P of A.
+
+Authors:
+
+   The authors of the code itself are Stefan I. Larimore and Timothy A.
+   Davis (davis at cise.ufl.edu), University of Florida.  The algorithm
+   was developed in collaboration with John Gilbert, Xerox PARC, and
+   Esmond Ng, Oak Ridge National Laboratory.
+
+Acknowledgements:
+
+   This work was supported by the National Science Foundation, under
+   grants DMS-9504974 and DMS-9803599.
+
+License:
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+   USA.
+
+   Permission is hereby granted to use or copy this program under the
+   terms of the GNU LGPL, provided that the Copyright, this License,
+   and the Availability of the original version is retained on all
+   copies.  User documentation of any code that uses this code or any
+   modified version of this code must cite the Copyright, this License,
+   the Availability note, and "Used by permission."  Permission to
+   modify the code and to distribute modified code is granted, provided
+   the Copyright, this License, and the Availability note are retained,
+   and a notice that the code was modified is included.
+
+   COLAMD is also available under alternate licenses, contact T. Davis
+   for details.
+
+Availability:
+
+   The colamd/symamd library is available at:
+
+   http://www.cise.ufl.edu/research/sparse/colamd/
+
+References:
+
+   T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate
+   column minimum degree ordering algorithm, ACM Transactions on
+   Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+   T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836:
+   COLAMD, an approximate column minimum degree ordering algorithm, ACM
+   Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+   2004.
Index: deps/glpk/src/colamd/colamd.c
===================================================================
--- deps/glpk/src/colamd/colamd.c	(revision 9)
+++ deps/glpk/src/colamd/colamd.c	(revision 9)
@@ -0,0 +1,3622 @@
+/* ========================================================================== */
+/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD
+
+    colamd:  an approximate minimum degree column ordering algorithm,
+        for LU factorization of symmetric or unsymmetric matrices,
+        QR factorization, least squares, interior point methods for
+        linear programming problems, and other related problems.
+
+    symamd:  an approximate minimum degree ordering algorithm for Cholesky
+        factorization of symmetric matrices.
+
+    Purpose:
+
+        Colamd computes a permutation Q such that the Cholesky factorization of
+        (AQ)'(AQ) has less fill-in and requires fewer floating point operations
+        than A'A.  This also provides a good ordering for sparse partial
+        pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+        factorization, and P is computed during numerical factorization via
+        conventional partial pivoting with row interchanges.  Colamd is the
+        column ordering method used in SuperLU, part of the ScaLAPACK library.
+        It is also available as built-in function in MATLAB Version 6,
+        available from MathWorks, Inc. (http://www.mathworks.com).  This
+        routine can be used in place of colmmd in MATLAB.
+
+        Symamd computes a permutation P of a symmetric matrix A such that the
+        Cholesky factorization of PAP' has less fill-in and requires fewer
+        floating point operations than A.  Symamd constructs a matrix M such
+        that M'M has the same nonzero pattern of A, and then orders the columns
+        of M using colmmd.  The column ordering of M is then returned as the
+        row and column ordering P of A. 
+
+    Authors:
+
+        The authors of the code itself are Stefan I. Larimore and Timothy A.
+        Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+        developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+        Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+        This work was supported by the National Science Foundation, under
+        grants DMS-9504974 and DMS-9803599.
+
+    Copyright and License:
+
+        Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
+        COLAMD is also available under alternate licenses, contact T. Davis
+        for details.
+
+        This library is free software; you can redistribute it and/or
+        modify it under the terms of the GNU Lesser General Public
+        License as published by the Free Software Foundation; either
+        version 2.1 of the License, or (at your option) any later version.
+
+        This library is distributed in the hope that it will be useful,
+        but WITHOUT ANY WARRANTY; without even the implied warranty of
+        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+        Lesser General Public License for more details.
+
+        You should have received a copy of the GNU Lesser General Public
+        License along with this library; if not, write to the Free Software
+        Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+        USA
+
+        Permission is hereby granted to use or copy this program under the
+        terms of the GNU LGPL, provided that the Copyright, this License,
+        and the Availability of the original version is retained on all copies.
+        User documentation of any code that uses this code or any modified
+        version of this code must cite the Copyright, this License, the
+        Availability note, and "Used by permission." Permission to modify
+        the code and to distribute modified code is granted, provided the
+        Copyright, this License, and the Availability note are retained,
+        and a notice that the code was modified is included.
+
+    Availability:
+
+        The colamd/symamd library is available at
+
+            http://www.cise.ufl.edu/research/sparse/colamd/
+
+        This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
+        file.  It requires the colamd.h file.  It is required by the colamdmex.c
+        and symamdmex.c files, for the MATLAB interface to colamd and symamd.
+        Appears as ACM Algorithm 836.
+
+    See the ChangeLog file for changes since Version 1.0.
+
+    References:
+
+        T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+        minimum degree ordering algorithm, ACM Transactions on Mathematical
+        Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+        T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+        an approximate column minimum degree ordering algorithm, ACM
+        Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+        2004.
+
+*/
+
+/* ========================================================================== */
+/* === Description of user-callable routines ================================ */
+/* ========================================================================== */
+
+/* COLAMD includes both int and UF_long versions of all its routines.  The
+ * description below is for the int version.  For UF_long, all int arguments
+ * become UF_long.  UF_long is normally defined as long, except for WIN64.
+
+    ----------------------------------------------------------------------------
+    colamd_recommended:
+    ----------------------------------------------------------------------------
+
+        C syntax:
+
+            #include "colamd.h"
+            size_t colamd_recommended (int nnz, int n_row, int n_col) ;
+            size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
+                UF_long n_col) ;
+
+        Purpose:
+
+            Returns recommended value of Alen for use by colamd.  Returns 0
+            if any input argument is negative.  The use of this routine
+            is optional.  Not needed for symamd, which dynamically allocates
+            its own memory.
+
+            Note that in v2.4 and earlier, these routines returned int or long.
+            They now return a value of type size_t.
+
+        Arguments (all input arguments):
+
+            int nnz ;           Number of nonzeros in the matrix A.  This must
+                                be the same value as p [n_col] in the call to
+                                colamd - otherwise you will get a wrong value
+                                of the recommended memory to use.
+
+            int n_row ;         Number of rows in the matrix A.
+
+            int n_col ;         Number of columns in the matrix A.
+
+    ----------------------------------------------------------------------------
+    colamd_set_defaults:
+    ----------------------------------------------------------------------------
+
+        C syntax:
+
+            #include "colamd.h"
+            colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
+            colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
+
+        Purpose:
+
+            Sets the default parameters.  The use of this routine is optional.
+
+        Arguments:
+
+            double knobs [COLAMD_KNOBS] ;       Output only.
+
+                NOTE: the meaning of the dense row/col knobs has changed in v2.4
+
+                knobs [0] and knobs [1] control dense row and col detection:
+
+                Colamd: rows with more than
+                max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
+                entries are removed prior to ordering.  Columns with more than
+                max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
+                entries are removed prior to
+                ordering, and placed last in the output column ordering. 
+
+                Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
+                Rows and columns with more than
+                max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
+                entries are removed prior to ordering, and placed last in the
+                output ordering.
+
+                COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
+                respectively, in colamd.h.  Default values of these two knobs
+                are both 10.  Currently, only knobs [0] and knobs [1] are
+                used, but future versions may use more knobs.  If so, they will
+                be properly set to their defaults by the future version of
+                colamd_set_defaults, so that the code that calls colamd will
+                not need to change, assuming that you either use
+                colamd_set_defaults, or pass a (double *) NULL pointer as the
+                knobs array to colamd or symamd.
+
+            knobs [2]: aggressive absorption
+
+                knobs [COLAMD_AGGRESSIVE] controls whether or not to do
+                aggressive absorption during the ordering.  Default is TRUE.
+
+
+    ----------------------------------------------------------------------------
+    colamd:
+    ----------------------------------------------------------------------------
+
+        C syntax:
+
+            #include "colamd.h"
+            int colamd (int n_row, int n_col, int Alen, int *A, int *p,
+                double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
+            UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
+                UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
+                UF_long stats [COLAMD_STATS]) ;
+
+        Purpose:
+
+            Computes a column ordering (Q) of A such that P(AQ)=LU or
+            (AQ)'AQ=LL' have less fill-in and require fewer floating point
+            operations than factorizing the unpermuted matrix A or A'A,
+            respectively.
+            
+        Returns:
+
+            TRUE (1) if successful, FALSE (0) otherwise.
+
+        Arguments:
+
+            int n_row ;         Input argument.
+
+                Number of rows in the matrix A.
+                Restriction:  n_row >= 0.
+                Colamd returns FALSE if n_row is negative.
+
+            int n_col ;         Input argument.
+
+                Number of columns in the matrix A.
+                Restriction:  n_col >= 0.
+                Colamd returns FALSE if n_col is negative.
+
+            int Alen ;          Input argument.
+
+                Restriction (see note):
+                Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
+                Colamd returns FALSE if these conditions are not met.
+
+                Note:  this restriction makes an modest assumption regarding
+                the size of the two typedef's structures in colamd.h.
+                We do, however, guarantee that
+
+                        Alen >= colamd_recommended (nnz, n_row, n_col)
+
+                will be sufficient.  Note: the macro version does not check
+                for integer overflow, and thus is not recommended.  Use
+                the colamd_recommended routine instead.
+
+            int A [Alen] ;      Input argument, undefined on output.
+
+                A is an integer array of size Alen.  Alen must be at least as
+                large as the bare minimum value given above, but this is very
+                low, and can result in excessive run time.  For best
+                performance, we recommend that Alen be greater than or equal to
+                colamd_recommended (nnz, n_row, n_col), which adds
+                nnz/5 to the bare minimum value given above.
+
+                On input, the row indices of the entries in column c of the
+                matrix are held in A [(p [c]) ... (p [c+1]-1)].  The row indices
+                in a given column c need not be in ascending order, and
+                duplicate row indices may be be present.  However, colamd will
+                work a little faster if both of these conditions are met
+                (Colamd puts the matrix into this format, if it finds that the
+                the conditions are not met).
+
+                The matrix is 0-based.  That is, rows are in the range 0 to
+                n_row-1, and columns are in the range 0 to n_col-1.  Colamd
+                returns FALSE if any row index is out of range.
+
+                The contents of A are modified during ordering, and are
+                undefined on output.
+
+            int p [n_col+1] ;   Both input and output argument.
+
+                p is an integer array of size n_col+1.  On input, it holds the
+                "pointers" for the column form of the matrix A.  Column c of
+                the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+                entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+                for all c in the range 0 to n_col-1.  The value p [n_col] is
+                thus the total number of entries in the pattern of the matrix A.
+                Colamd returns FALSE if these conditions are not met.
+
+                On output, if colamd returns TRUE, the array p holds the column
+                permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
+                the first column index in the new ordering, and p [n_col-1] is
+                the last.  That is, p [k] = j means that column j of A is the
+                kth pivot column, in AQ, where k is in the range 0 to n_col-1
+                (p [0] = j means that column j of A is the first column in AQ).
+
+                If colamd returns FALSE, then no permutation is returned, and
+                p is undefined on output.
+
+            double knobs [COLAMD_KNOBS] ;       Input argument.
+
+                See colamd_set_defaults for a description.
+
+            int stats [COLAMD_STATS] ;          Output argument.
+
+                Statistics on the ordering, and error status.
+                See colamd.h for related definitions.
+                Colamd returns FALSE if stats is not present.
+
+                stats [0]:  number of dense or empty rows ignored.
+
+                stats [1]:  number of dense or empty columns ignored (and
+                                ordered last in the output permutation p)
+                                Note that a row can become "empty" if it
+                                contains only "dense" and/or "empty" columns,
+                                and similarly a column can become "empty" if it
+                                only contains "dense" and/or "empty" rows.
+
+                stats [2]:  number of garbage collections performed.
+                                This can be excessively high if Alen is close
+                                to the minimum required value.
+
+                stats [3]:  status code.  < 0 is an error code.
+                            > 1 is a warning or notice.
+
+                        0       OK.  Each column of the input matrix contained
+                                row indices in increasing order, with no
+                                duplicates.
+
+                        1       OK, but columns of input matrix were jumbled
+                                (unsorted columns or duplicate entries).  Colamd
+                                had to do some extra work to sort the matrix
+                                first and remove duplicate entries, but it
+                                still was able to return a valid permutation
+                                (return value of colamd was TRUE).
+
+                                        stats [4]: highest numbered column that
+                                                is unsorted or has duplicate
+                                                entries.
+                                        stats [5]: last seen duplicate or
+                                                unsorted row index.
+                                        stats [6]: number of duplicate or
+                                                unsorted row indices.
+
+                        -1      A is a null pointer
+
+                        -2      p is a null pointer
+
+                        -3      n_row is negative
+
+                                        stats [4]: n_row
+
+                        -4      n_col is negative
+
+                                        stats [4]: n_col
+
+                        -5      number of nonzeros in matrix is negative
+
+                                        stats [4]: number of nonzeros, p [n_col]
+
+                        -6      p [0] is nonzero
+
+                                        stats [4]: p [0]
+
+                        -7      A is too small
+
+                                        stats [4]: required size
+                                        stats [5]: actual size (Alen)
+
+                        -8      a column has a negative number of entries
+
+                                        stats [4]: column with < 0 entries
+                                        stats [5]: number of entries in col
+
+                        -9      a row index is out of bounds
+
+                                        stats [4]: column with bad row index
+                                        stats [5]: bad row index
+                                        stats [6]: n_row, # of rows of matrx
+
+                        -10     (unused; see symamd.c)
+
+                        -999    (unused; see symamd.c)
+
+                Future versions may return more statistics in the stats array.
+
+        Example:
+        
+            See http://www.cise.ufl.edu/research/sparse/colamd/example.c
+            for a complete example.
+
+            To order the columns of a 5-by-4 matrix with 11 nonzero entries in
+            the following nonzero pattern
+
+                x 0 x 0
+                x 0 x x
+                0 x x 0
+                0 0 x x
+                x x 0 0
+
+            with default knobs and no output statistics, do the following:
+
+                #include "colamd.h"
+                #define ALEN 100
+                int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
+                int p [ ] = {0, 3, 5, 9, 11} ;
+                int stats [COLAMD_STATS] ;
+                colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
+
+            The permutation is returned in the array p, and A is destroyed.
+
+    ----------------------------------------------------------------------------
+    symamd:
+    ----------------------------------------------------------------------------
+
+        C syntax:
+
+            #include "colamd.h"
+            int symamd (int n, int *A, int *p, int *perm,
+                double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
+                void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+            UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
+                double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
+                void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+
+        Purpose:
+
+            The symamd routine computes an ordering P of a symmetric sparse
+            matrix A such that the Cholesky factorization PAP' = LL' remains
+            sparse.  It is based on a column ordering of a matrix M constructed
+            so that the nonzero pattern of M'M is the same as A.  The matrix A
+            is assumed to be symmetric; only the strictly lower triangular part
+            is accessed.  You must pass your selected memory allocator (usually
+            calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
+            memory for the temporary matrix M.
+
+        Returns:
+
+            TRUE (1) if successful, FALSE (0) otherwise.
+
+        Arguments:
+
+            int n ;             Input argument.
+
+                Number of rows and columns in the symmetrix matrix A.
+                Restriction:  n >= 0.
+                Symamd returns FALSE if n is negative.
+
+            int A [nnz] ;       Input argument.
+
+                A is an integer array of size nnz, where nnz = p [n].
+                
+                The row indices of the entries in column c of the matrix are
+                held in A [(p [c]) ... (p [c+1]-1)].  The row indices in a
+                given column c need not be in ascending order, and duplicate
+                row indices may be present.  However, symamd will run faster
+                if the columns are in sorted order with no duplicate entries. 
+
+                The matrix is 0-based.  That is, rows are in the range 0 to
+                n-1, and columns are in the range 0 to n-1.  Symamd
+                returns FALSE if any row index is out of range.
+
+                The contents of A are not modified.
+
+            int p [n+1] ;       Input argument.
+
+                p is an integer array of size n+1.  On input, it holds the
+                "pointers" for the column form of the matrix A.  Column c of
+                the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+                entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+                for all c in the range 0 to n-1.  The value p [n] is
+                thus the total number of entries in the pattern of the matrix A.
+                Symamd returns FALSE if these conditions are not met.
+
+                The contents of p are not modified.
+
+            int perm [n+1] ;    Output argument.
+
+                On output, if symamd returns TRUE, the array perm holds the
+                permutation P, where perm [0] is the first index in the new
+                ordering, and perm [n-1] is the last.  That is, perm [k] = j
+                means that row and column j of A is the kth column in PAP',
+                where k is in the range 0 to n-1 (perm [0] = j means
+                that row and column j of A are the first row and column in
+                PAP').  The array is used as a workspace during the ordering,
+                which is why it must be of length n+1, not just n.
+
+            double knobs [COLAMD_KNOBS] ;       Input argument.
+
+                See colamd_set_defaults for a description.
+
+            int stats [COLAMD_STATS] ;          Output argument.
+
+                Statistics on the ordering, and error status.
+                See colamd.h for related definitions.
+                Symamd returns FALSE if stats is not present.
+
+                stats [0]:  number of dense or empty row and columns ignored
+                                (and ordered last in the output permutation 
+                                perm).  Note that a row/column can become
+                                "empty" if it contains only "dense" and/or
+                                "empty" columns/rows.
+
+                stats [1]:  (same as stats [0])
+
+                stats [2]:  number of garbage collections performed.
+
+                stats [3]:  status code.  < 0 is an error code.
+                            > 1 is a warning or notice.
+
+                        0       OK.  Each column of the input matrix contained
+                                row indices in increasing order, with no
+                                duplicates.
+
+                        1       OK, but columns of input matrix were jumbled
+                                (unsorted columns or duplicate entries).  Symamd
+                                had to do some extra work to sort the matrix
+                                first and remove duplicate entries, but it
+                                still was able to return a valid permutation
+                                (return value of symamd was TRUE).
+
+                                        stats [4]: highest numbered column that
+                                                is unsorted or has duplicate
+                                                entries.
+                                        stats [5]: last seen duplicate or
+                                                unsorted row index.
+                                        stats [6]: number of duplicate or
+                                                unsorted row indices.
+
+                        -1      A is a null pointer
+
+                        -2      p is a null pointer
+
+                        -3      (unused, see colamd.c)
+
+                        -4      n is negative
+
+                                        stats [4]: n
+
+                        -5      number of nonzeros in matrix is negative
+
+                                        stats [4]: # of nonzeros (p [n]).
+
+                        -6      p [0] is nonzero
+
+                                        stats [4]: p [0]
+
+                        -7      (unused)
+
+                        -8      a column has a negative number of entries
+
+                                        stats [4]: column with < 0 entries
+                                        stats [5]: number of entries in col
+
+                        -9      a row index is out of bounds
+
+                                        stats [4]: column with bad row index
+                                        stats [5]: bad row index
+                                        stats [6]: n_row, # of rows of matrx
+
+                        -10     out of memory (unable to allocate temporary
+                                workspace for M or count arrays using the
+                                "allocate" routine passed into symamd).
+
+                Future versions may return more statistics in the stats array.
+
+            void * (*allocate) (size_t, size_t)
+
+                A pointer to a function providing memory allocation.  The
+                allocated memory must be returned initialized to zero.  For a
+                C application, this argument should normally be a pointer to
+                calloc.  For a MATLAB mexFunction, the routine mxCalloc is
+                passed instead.
+
+            void (*release) (size_t, size_t)
+
+                A pointer to a function that frees memory allocated by the
+                memory allocation routine above.  For a C application, this
+                argument should normally be a pointer to free.  For a MATLAB
+                mexFunction, the routine mxFree is passed instead.
+
+
+    ----------------------------------------------------------------------------
+    colamd_report:
+    ----------------------------------------------------------------------------
+
+        C syntax:
+
+            #include "colamd.h"
+            colamd_report (int stats [COLAMD_STATS]) ;
+            colamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+        Purpose:
+
+            Prints the error status and statistics recorded in the stats
+            array on the standard error output (for a standard C routine)
+            or on the MATLAB output (for a mexFunction).
+
+        Arguments:
+
+            int stats [COLAMD_STATS] ;  Input only.  Statistics from colamd.
+
+
+    ----------------------------------------------------------------------------
+    symamd_report:
+    ----------------------------------------------------------------------------
+
+        C syntax:
+
+            #include "colamd.h"
+            symamd_report (int stats [COLAMD_STATS]) ;
+            symamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+        Purpose:
+
+            Prints the error status and statistics recorded in the stats
+            array on the standard error output (for a standard C routine)
+            or on the MATLAB output (for a mexFunction).
+
+        Arguments:
+
+            int stats [COLAMD_STATS] ;  Input only.  Statistics from symamd.
+
+
+*/
+
+/* ========================================================================== */
+/* === Scaffolding code definitions  ======================================== */
+/* ========================================================================== */
+
+/* Ensure that debugging is turned off: */
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/* turn on debugging by uncommenting the following line
+ #undef NDEBUG
+*/
+
+/*
+   Our "scaffolding code" philosophy:  In our opinion, well-written library
+   code should keep its "debugging" code, and just normally have it turned off
+   by the compiler so as not to interfere with performance.  This serves
+   several purposes:
+
+   (1) assertions act as comments to the reader, telling you what the code
+        expects at that point.  All assertions will always be true (unless
+        there really is a bug, of course).
+
+   (2) leaving in the scaffolding code assists anyone who would like to modify
+        the code, or understand the algorithm (by reading the debugging output,
+        one can get a glimpse into what the code is doing).
+
+   (3) (gasp!) for actually finding bugs.  This code has been heavily tested
+        and "should" be fully functional and bug-free ... but you never know...
+
+    The code will become outrageously slow when debugging is
+    enabled.  To control the level of debugging output, set an environment
+    variable D to 0 (little), 1 (some), 2, 3, or 4 (lots).  When debugging,
+    you should see the following message on the standard output:
+
+        colamd: debug version, D = 1 (THIS WILL BE SLOW!)
+
+    or a similar message for symamd.  If you don't, then debugging has not
+    been enabled.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+
+#if 0 /* by mao */
+#include <limits.h>
+#include <math.h>
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#include "matrix.h"
+#endif /* MATLAB_MEX_FILE */
+
+#if !defined (NPRINT) || !defined (NDEBUG)
+#include <stdio.h>
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+#endif
+
+/* ========================================================================== */
+/* === int or UF_long ======================================================= */
+/* ========================================================================== */
+
+#if 0 /* by mao */
+/* define UF_long */
+#include "UFconfig.h"
+#endif
+
+#ifdef DLONG
+
+#define Int UF_long
+#define ID  UF_long_id
+#define Int_MAX UF_long_max
+
+#define COLAMD_recommended colamd_l_recommended
+#define COLAMD_set_defaults colamd_l_set_defaults
+#define COLAMD_MAIN colamd_l
+#define SYMAMD_MAIN symamd_l
+#define COLAMD_report colamd_l_report
+#define SYMAMD_report symamd_l_report
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define COLAMD_recommended colamd_recommended
+#define COLAMD_set_defaults colamd_set_defaults
+#define COLAMD_MAIN colamd
+#define SYMAMD_MAIN symamd
+#define COLAMD_report colamd_report
+#define SYMAMD_report symamd_report
+
+#endif
+
+/* ========================================================================== */
+/* === Row and Column structures ============================================ */
+/* ========================================================================== */
+
+/* User code that makes use of the colamd/symamd routines need not directly */
+/* reference these structures.  They are used only for colamd_recommended. */
+
+typedef struct Colamd_Col_struct
+{
+    Int start ;         /* index for A of first row in this column, or DEAD */
+                        /* if column is dead */
+    Int length ;        /* number of rows in this column */
+    union
+    {
+        Int thickness ; /* number of original columns represented by this */
+                        /* col, if the column is alive */
+        Int parent ;    /* parent in parent tree super-column structure, if */
+                        /* the column is dead */
+    } shared1 ;
+    union
+    {
+        Int score ;     /* the score used to maintain heap, if col is alive */
+        Int order ;     /* pivot ordering of this column, if col is dead */
+    } shared2 ;
+    union
+    {
+        Int headhash ;  /* head of a hash bucket, if col is at the head of */
+                        /* a degree list */
+        Int hash ;      /* hash value, if col is not in a degree list */
+        Int prev ;      /* previous column in degree list, if col is in a */
+                        /* degree list (but not at the head of a degree list) */
+    } shared3 ;
+    union
+    {
+        Int degree_next ;       /* next column, if col is in a degree list */
+        Int hash_next ;         /* next column, if col is in a hash list */
+    } shared4 ;
+
+} Colamd_Col ;
+
+typedef struct Colamd_Row_struct
+{
+    Int start ;         /* index for A of first col in this row */
+    Int length ;        /* number of principal columns in this row */
+    union
+    {
+        Int degree ;    /* number of principal & non-principal columns in row */
+        Int p ;         /* used as a row pointer in init_rows_cols () */
+    } shared1 ;
+    union
+    {
+        Int mark ;      /* for computing set differences and marking dead rows*/
+        Int first_column ;/* first column in row (used in garbage collection) */
+    } shared2 ;
+
+} Colamd_Row ;
+
+/* ========================================================================== */
+/* === Definitions ========================================================== */
+/* ========================================================================== */
+
+/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
+#define PUBLIC
+#define PRIVATE static
+
+#define DENSE_DEGREE(alpha,n) \
+    ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* Change for version 2.1:  define TRUE and FALSE only if not yet defined */  
+/* -------------------------------------------------------------------------- */
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+#define EMPTY   (-1)
+
+/* Row and column status */
+#define ALIVE   (0)
+#define DEAD    (-1)
+
+/* Column status */
+#define DEAD_PRINCIPAL          (-1)
+#define DEAD_NON_PRINCIPAL      (-2)
+
+/* Macros for row and column status update and checking. */
+#define ROW_IS_DEAD(r)                  ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
+#define ROW_IS_MARKED_DEAD(row_mark)    (row_mark < ALIVE)
+#define ROW_IS_ALIVE(r)                 (Row [r].shared2.mark >= ALIVE)
+#define COL_IS_DEAD(c)                  (Col [c].start < ALIVE)
+#define COL_IS_ALIVE(c)                 (Col [c].start >= ALIVE)
+#define COL_IS_DEAD_PRINCIPAL(c)        (Col [c].start == DEAD_PRINCIPAL)
+#define KILL_ROW(r)                     { Row [r].shared2.mark = DEAD ; }
+#define KILL_PRINCIPAL_COL(c)           { Col [c].start = DEAD_PRINCIPAL ; }
+#define KILL_NON_PRINCIPAL_COL(c)       { Col [c].start = DEAD_NON_PRINCIPAL ; }
+
+/* ========================================================================== */
+/* === Colamd reporting mechanism =========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
+#define INDEX(i) ((i)+1)
+#else
+/* In C, matrices are 0-based and indices are reported as such in *_report */
+#define INDEX(i) (i)
+#endif
+
+/* All output goes through the PRINTF macro.  */
+#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
+
+/* ========================================================================== */
+/* === Prototypes of PRIVATE routines ======================================= */
+/* ========================================================================== */
+
+PRIVATE Int init_rows_cols
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int p [],
+    Int stats [COLAMD_STATS]
+) ;
+
+PRIVATE void init_scoring
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    double knobs [COLAMD_KNOBS],
+    Int *p_n_row2,
+    Int *p_n_col2,
+    Int *p_max_deg
+) ;
+
+PRIVATE Int find_ordering
+(
+    Int n_row,
+    Int n_col,
+    Int Alen,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int n_col2,
+    Int max_deg,
+    Int pfree,
+    Int aggressive
+) ;
+
+PRIVATE void order_children
+(
+    Int n_col,
+    Colamd_Col Col [],
+    Int p []
+) ;
+
+PRIVATE void detect_super_cols
+(
+
+#ifndef NDEBUG
+    Int n_col,
+    Colamd_Row Row [],
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int row_start,
+    Int row_length
+) ;
+
+PRIVATE Int garbage_collection
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int *pfree
+) ;
+
+PRIVATE Int clear_mark
+(
+    Int tag_mark,
+    Int max_mark,
+    Int n_row,
+    Colamd_Row Row []
+) ;
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+) ;
+
+/* ========================================================================== */
+/* === Debugging prototypes and definitions ================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+#if 0 /* by mao */
+#include <assert.h>
+#endif
+
+/* colamd_debug is the *ONLY* global variable, and is only */
+/* present when debugging */
+
+PRIVATE Int colamd_debug = 0 ;  /* debug print level */
+
+#define DEBUG0(params) { PRINTF (params) ; }
+#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
+#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
+#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
+#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
+
+#if 0 /* by mao */
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif /* MATLAB_MEX_FILE */
+#else
+#define ASSERT xassert
+#endif
+
+PRIVATE void colamd_get_debug   /* gets the debug print level from getenv */
+(
+    char *method
+) ;
+
+PRIVATE void debug_deg_lists
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+) ;
+
+PRIVATE void debug_mark
+(
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+) ;
+
+PRIVATE void debug_matrix
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+) ;
+
+PRIVATE void debug_structures
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+) ;
+
+#else /* NDEBUG */
+
+/* === No debugging ========================================================= */
+
+#define DEBUG0(params) ;
+#define DEBUG1(params) ;
+#define DEBUG2(params) ;
+#define DEBUG3(params) ;
+#define DEBUG4(params) ;
+
+#define ASSERT(expression)
+
+#endif /* NDEBUG */
+
+/* ========================================================================== */
+/* === USER-CALLABLE ROUTINES: ============================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === colamd_recommended =================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_recommended routine returns the suggested size for Alen.  This
+    value has been determined to provide good balance between the number of
+    garbage collections and the memory requirements for colamd.  If any
+    argument is negative, or if integer overflow occurs, a 0 is returned as an
+    error condition.  2*nnz space is required for the row and column
+    indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
+    required for the Col and Row arrays, respectively, which are internal to
+    colamd (roughly 6*n_col + 4*n_row).  An additional n_col space is the
+    minimal amount of "elbow room", and nnz/5 more space is recommended for
+    run time efficiency.
+
+    Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
+
+    This function is not needed when using symamd.
+*/
+
+/* add two values of type size_t, and check for integer overflow */
+static size_t t_add (size_t a, size_t b, int *ok)
+{
+    (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
+    return ((*ok) ? (a + b) : 0) ;
+}
+
+/* compute a*k where k is a small integer, and check for integer overflow */
+static size_t t_mult (size_t a, size_t k, int *ok)
+{
+    size_t i, s = 0 ;
+    for (i = 0 ; i < k ; i++)
+    {
+        s = t_add (s, a, ok) ;
+    }
+    return (s) ;
+}
+
+/* size of the Col and Row structures */
+#define COLAMD_C(n_col,ok) \
+    ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
+
+#define COLAMD_R(n_row,ok) \
+    ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
+
+
+PUBLIC size_t COLAMD_recommended        /* returns recommended value of Alen. */
+(
+    /* === Parameters ======================================================= */
+
+    Int nnz,                    /* number of nonzeros in A */
+    Int n_row,                  /* number of rows in A */
+    Int n_col                   /* number of columns in A */
+)
+{
+    size_t s, c, r ;
+    int ok = TRUE ;
+    if (nnz < 0 || n_row < 0 || n_col < 0)
+    {
+        return (0) ;
+    }
+    s = t_mult (nnz, 2, &ok) ;      /* 2*nnz */
+    c = COLAMD_C (n_col, &ok) ;     /* size of column structures */
+    r = COLAMD_R (n_row, &ok) ;     /* size of row structures */
+    s = t_add (s, c, &ok) ;
+    s = t_add (s, r, &ok) ;
+    s = t_add (s, n_col, &ok) ;     /* elbow room */
+    s = t_add (s, nnz/5, &ok) ;     /* elbow room */
+    ok = ok && (s < Int_MAX) ;
+    return (ok ? s : 0) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_set_defaults ================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_set_defaults routine sets the default values of the user-
+    controllable parameters for colamd and symamd:
+
+        Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
+        entries are removed prior to ordering.  Columns with more than
+        max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
+        prior to ordering, and placed last in the output column ordering. 
+
+        Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
+        entries are removed prior to ordering, and placed last in the
+        output ordering.
+
+        knobs [0]       dense row control
+
+        knobs [1]       dense column control
+
+        knobs [2]       if nonzero, do aggresive absorption
+
+        knobs [3..19]   unused, but future versions might use this
+
+*/
+
+PUBLIC void COLAMD_set_defaults
+(
+    /* === Parameters ======================================================= */
+
+    double knobs [COLAMD_KNOBS]         /* knob array */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+
+    if (!knobs)
+    {
+        return ;                        /* no knobs to initialize */
+    }
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+        knobs [i] = 0 ;
+    }
+    knobs [COLAMD_DENSE_ROW] = 10 ;
+    knobs [COLAMD_DENSE_COL] = 10 ;
+    knobs [COLAMD_AGGRESSIVE] = TRUE ;  /* default: do aggressive absorption*/
+}
+
+
+/* ========================================================================== */
+/* === symamd =============================================================== */
+/* ========================================================================== */
+
+PUBLIC Int SYMAMD_MAIN                  /* return TRUE if OK, FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n,                              /* number of rows and columns of A */
+    Int A [],                           /* row indices of A */
+    Int p [],                           /* column pointers of A */
+    Int perm [],                        /* output permutation, size n+1 */
+    double knobs [COLAMD_KNOBS],        /* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS],           /* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+                                        /* pointer to calloc (ANSI C) or */
+                                        /* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+                                        /* pointer to free (ANSI C) or */
+                                        /* mxFree (for MATLAB mexFunction) */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *count ;                /* length of each column of M, and col pointer*/
+    Int *mark ;                 /* mark array for finding duplicate entries */
+    Int *M ;                    /* row indices of matrix M */
+    size_t Mlen ;               /* length of M */
+    Int n_row ;                 /* number of rows in M */
+    Int nnz ;                   /* number of entries in A */
+    Int i ;                     /* row index of A */
+    Int j ;                     /* column index of A */
+    Int k ;                     /* row index of M */ 
+    Int mnz ;                   /* number of nonzeros in M */
+    Int pp ;                    /* index into a column of A */
+    Int last_row ;              /* last row seen in the current column */
+    Int length ;                /* number of nonzeros in a column */
+
+    double cknobs [COLAMD_KNOBS] ;              /* knobs for colamd */
+    double default_knobs [COLAMD_KNOBS] ;       /* default knobs for colamd */
+
+#ifndef NDEBUG
+    colamd_get_debug ("symamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+        DEBUG0 (("symamd: stats not present\n")) ;
+        return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+        stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+        DEBUG0 (("symamd: A not present\n")) ;
+        return (FALSE) ;
+    }
+
+    if (!p)             /* p is not present */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+        DEBUG0 (("symamd: p not present\n")) ;
+        return (FALSE) ;
+    }
+
+    if (n < 0)          /* n must be >= 0 */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+        stats [COLAMD_INFO1] = n ;
+        DEBUG0 (("symamd: n negative %d\n", n)) ;
+        return (FALSE) ;
+    }
+
+    nnz = p [n] ;
+    if (nnz < 0)        /* nnz must be >= 0 */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+        stats [COLAMD_INFO1] = nnz ;
+        DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
+        return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+        stats [COLAMD_INFO1] = p [0] ;
+        DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
+        return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+        COLAMD_set_defaults (default_knobs) ;
+        knobs = default_knobs ;
+    }
+
+    /* === Allocate count and mark ========================================== */
+
+    count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!count)
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+        DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
+        return (FALSE) ;
+    }
+
+    mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!mark)
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+        (*release) ((void *) count) ;
+        DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
+        return (FALSE) ;
+    }
+
+    /* === Compute column counts of M, check if A is valid ================== */
+
+    stats [COLAMD_INFO3] = 0 ;  /* number of duplicate or unsorted row indices*/
+
+    for (i = 0 ; i < n ; i++)
+    {
+        mark [i] = -1 ;
+    }
+
+    for (j = 0 ; j < n ; j++)
+    {
+        last_row = -1 ;
+
+        length = p [j+1] - p [j] ;
+        if (length < 0)
+        {
+            /* column pointers must be non-decreasing */
+            stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+            stats [COLAMD_INFO1] = j ;
+            stats [COLAMD_INFO2] = length ;
+            (*release) ((void *) count) ;
+            (*release) ((void *) mark) ;
+            DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
+            return (FALSE) ;
+        }
+
+        for (pp = p [j] ; pp < p [j+1] ; pp++)
+        {
+            i = A [pp] ;
+            if (i < 0 || i >= n)
+            {
+                /* row index i, in column j, is out of bounds */
+                stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+                stats [COLAMD_INFO1] = j ;
+                stats [COLAMD_INFO2] = i ;
+                stats [COLAMD_INFO3] = n ;
+                (*release) ((void *) count) ;
+                (*release) ((void *) mark) ;
+                DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
+                return (FALSE) ;
+            }
+
+            if (i <= last_row || mark [i] == j)
+            {
+                /* row index is unsorted or repeated (or both), thus col */
+                /* is jumbled.  This is a notice, not an error condition. */
+                stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+                stats [COLAMD_INFO1] = j ;
+                stats [COLAMD_INFO2] = i ;
+                (stats [COLAMD_INFO3]) ++ ;
+                DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
+            }
+
+            if (i > j && mark [i] != j)
+            {
+                /* row k of M will contain column indices i and j */
+                count [i]++ ;
+                count [j]++ ;
+            }
+
+            /* mark the row as having been seen in this column */
+            mark [i] = j ;
+
+            last_row = i ;
+        }
+    }
+
+    /* v2.4: removed free(mark) */
+
+    /* === Compute column pointers of M ===================================== */
+
+    /* use output permutation, perm, for column pointers of M */
+    perm [0] = 0 ;
+    for (j = 1 ; j <= n ; j++)
+    {
+        perm [j] = perm [j-1] + count [j-1] ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+        count [j] = perm [j] ;
+    }
+
+    /* === Construct M ====================================================== */
+
+    mnz = perm [n] ;
+    n_row = mnz / 2 ;
+    Mlen = COLAMD_recommended (mnz, n_row, n) ;
+    M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
+    DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
+        n_row, n, mnz, (double) Mlen)) ;
+
+    if (!M)
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+        (*release) ((void *) count) ;
+        (*release) ((void *) mark) ;
+        DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
+        return (FALSE) ;
+    }
+
+    k = 0 ;
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK)
+    {
+        /* Matrix is OK */
+        for (j = 0 ; j < n ; j++)
+        {
+            ASSERT (p [j+1] - p [j] >= 0) ;
+            for (pp = p [j] ; pp < p [j+1] ; pp++)
+            {
+                i = A [pp] ;
+                ASSERT (i >= 0 && i < n) ;
+                if (i > j)
+                {
+                    /* row k of M contains column indices i and j */
+                    M [count [i]++] = k ;
+                    M [count [j]++] = k ;
+                    k++ ;
+                }
+            }
+        }
+    }
+    else
+    {
+        /* Matrix is jumbled.  Do not add duplicates to M.  Unsorted cols OK. */
+        DEBUG0 (("symamd: Duplicates in A.\n")) ;
+        for (i = 0 ; i < n ; i++)
+        {
+            mark [i] = -1 ;
+        }
+        for (j = 0 ; j < n ; j++)
+        {
+            ASSERT (p [j+1] - p [j] >= 0) ;
+            for (pp = p [j] ; pp < p [j+1] ; pp++)
+            {
+                i = A [pp] ;
+                ASSERT (i >= 0 && i < n) ;
+                if (i > j && mark [i] != j)
+                {
+                    /* row k of M contains column indices i and j */
+                    M [count [i]++] = k ;
+                    M [count [j]++] = k ;
+                    k++ ;
+                    mark [i] = j ;
+                }
+            }
+        }
+        /* v2.4: free(mark) moved below */
+    }
+
+    /* count and mark no longer needed */
+    (*release) ((void *) count) ;
+    (*release) ((void *) mark) ;        /* v2.4: free (mark) moved here */
+    ASSERT (k == n_row) ;
+
+    /* === Adjust the knobs for M =========================================== */
+
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+        cknobs [i] = knobs [i] ;
+    }
+
+    /* there are no dense rows in M */
+    cknobs [COLAMD_DENSE_ROW] = -1 ;
+    cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
+
+    /* === Order the columns of M =========================================== */
+
+    /* v2.4: colamd cannot fail here, so the error check is removed */
+    (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
+
+    /* Note that the output permutation is now in perm */
+
+    /* === get the statistics for symamd from colamd ======================== */
+
+    /* a dense column in colamd means a dense row and col in symamd */
+    stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
+
+    /* === Free M =========================================================== */
+
+    (*release) ((void *) M) ;
+    DEBUG0 (("symamd: done.\n")) ;
+    return (TRUE) ;
+
+}
+
+/* ========================================================================== */
+/* === colamd =============================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd routine computes a column ordering Q of a sparse matrix
+    A such that the LU factorization P(AQ) = LU remains sparse, where P is
+    selected via partial pivoting.   The routine can also be viewed as
+    providing a permutation Q such that the Cholesky factorization
+    (AQ)'(AQ) = LL' remains sparse.
+*/
+
+PUBLIC Int COLAMD_MAIN          /* returns TRUE if successful, FALSE otherwise*/
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                  /* number of rows in A */
+    Int n_col,                  /* number of columns in A */
+    Int Alen,                   /* length of A */
+    Int A [],                   /* row indices of A */
+    Int p [],                   /* pointers to columns in A */
+    double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS]    /* output statistics and error codes */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;                     /* loop index */
+    Int nnz ;                   /* nonzeros in A */
+    size_t Row_size ;           /* size of Row [], in integers */
+    size_t Col_size ;           /* size of Col [], in integers */
+    size_t need ;               /* minimum required length of A */
+    Colamd_Row *Row ;           /* pointer into A of Row [0..n_row] array */
+    Colamd_Col *Col ;           /* pointer into A of Col [0..n_col] array */
+    Int n_col2 ;                /* number of non-dense, non-empty columns */
+    Int n_row2 ;                /* number of non-dense, non-empty rows */
+    Int ngarbage ;              /* number of garbage collections performed */
+    Int max_deg ;               /* maximum row degree */
+    double default_knobs [COLAMD_KNOBS] ;       /* default knobs array */
+    Int aggressive ;            /* do aggressive absorption */
+    int ok ;
+
+#ifndef NDEBUG
+    colamd_get_debug ("colamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+        DEBUG0 (("colamd: stats not present\n")) ;
+        return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+        stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)             /* A is not present */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+        DEBUG0 (("colamd: A not present\n")) ;
+        return (FALSE) ;
+    }
+
+    if (!p)             /* p is not present */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+        DEBUG0 (("colamd: p not present\n")) ;
+        return (FALSE) ;
+    }
+
+    if (n_row < 0)      /* n_row must be >= 0 */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
+        stats [COLAMD_INFO1] = n_row ;
+        DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
+        return (FALSE) ;
+    }
+
+    if (n_col < 0)      /* n_col must be >= 0 */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+        stats [COLAMD_INFO1] = n_col ;
+        DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
+        return (FALSE) ;
+    }
+
+    nnz = p [n_col] ;
+    if (nnz < 0)        /* nnz must be >= 0 */
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+        stats [COLAMD_INFO1] = nnz ;
+        DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
+        return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+        stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+        stats [COLAMD_INFO1] = p [0] ;
+        DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
+        return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+        COLAMD_set_defaults (default_knobs) ;
+        knobs = default_knobs ;
+    }
+
+    aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
+
+    /* === Allocate the Row and Col arrays from array A ===================== */
+
+    ok = TRUE ;
+    Col_size = COLAMD_C (n_col, &ok) ;      /* size of Col array of structs */
+    Row_size = COLAMD_R (n_row, &ok) ;      /* size of Row array of structs */
+
+    /* need = 2*nnz + n_col + Col_size + Row_size ; */
+    need = t_mult (nnz, 2, &ok) ;
+    need = t_add (need, n_col, &ok) ;
+    need = t_add (need, Col_size, &ok) ;
+    need = t_add (need, Row_size, &ok) ;
+
+    if (!ok || need > (size_t) Alen || need > Int_MAX)
+    {
+        /* not enough space in array A to perform the ordering */
+        stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
+        stats [COLAMD_INFO1] = need ;
+        stats [COLAMD_INFO2] = Alen ;
+        DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
+        return (FALSE) ;
+    }
+
+    Alen -= Col_size + Row_size ;
+    Col = (Colamd_Col *) &A [Alen] ;
+    Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+    /* === Construct the row and column data structures ===================== */
+
+    if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
+    {
+        /* input matrix is invalid */
+        DEBUG0 (("colamd: Matrix invalid\n")) ;
+        return (FALSE) ;
+    }
+
+    /* === Initialize scores, kill dense rows/columns ======================= */
+
+    init_scoring (n_row, n_col, Row, Col, A, p, knobs,
+        &n_row2, &n_col2, &max_deg) ;
+
+    /* === Order the supercolumns =========================================== */
+
+    ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
+        n_col2, max_deg, 2*nnz, aggressive) ;
+
+    /* === Order the non-principal columns ================================== */
+
+    order_children (n_col, Col, p) ;
+
+    /* === Return statistics in stats ======================================= */
+
+    stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
+    stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
+    stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
+    DEBUG0 (("colamd: done.\n")) ; 
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void COLAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("colamd", stats) ;
+}
+
+
+/* ========================================================================== */
+/* === symamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void SYMAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("symamd", stats) ;
+}
+
+
+
+/* ========================================================================== */
+/* === NON-USER-CALLABLE ROUTINES: ========================================== */
+/* ========================================================================== */
+
+/* There are no user-callable routines beyond this point in the file */
+
+
+/* ========================================================================== */
+/* === init_rows_cols ======================================================= */
+/* ========================================================================== */
+
+/*
+    Takes the column form of the matrix in A and creates the row form of the
+    matrix.  Also, row and column attributes are stored in the Col and Row
+    structs.  If the columns are un-sorted or contain duplicate row indices,
+    this routine will also sort and remove duplicate row indices from the
+    column form of the matrix.  Returns FALSE if the matrix is invalid,
+    TRUE otherwise.  Not user-callable.
+*/
+
+PRIVATE Int init_rows_cols      /* returns TRUE if OK, or FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                  /* number of rows of A */
+    Int n_col,                  /* number of columns of A */
+    Colamd_Row Row [],          /* of size n_row+1 */
+    Colamd_Col Col [],          /* of size n_col+1 */
+    Int A [],                   /* row indices of A, of size Alen */
+    Int p [],                   /* pointers to columns in A, of size n_col+1 */
+    Int stats [COLAMD_STATS]    /* colamd statistics */ 
+)
+{
+    /* === Local variables ================================================== */
+
+    Int col ;                   /* a column index */
+    Int row ;                   /* a row index */
+    Int *cp ;                   /* a column pointer */
+    Int *cp_end ;               /* a pointer to the end of a column */
+    Int *rp ;                   /* a row pointer */
+    Int *rp_end ;               /* a pointer to the end of a row */
+    Int last_row ;              /* previous row */
+
+    /* === Initialize columns, and check column pointers ==================== */
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+        Col [col].start = p [col] ;
+        Col [col].length = p [col+1] - p [col] ;
+
+        if (Col [col].length < 0)
+        {
+            /* column pointers must be non-decreasing */
+            stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+            stats [COLAMD_INFO1] = col ;
+            stats [COLAMD_INFO2] = Col [col].length ;
+            DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
+            return (FALSE) ;
+        }
+
+        Col [col].shared1.thickness = 1 ;
+        Col [col].shared2.score = 0 ;
+        Col [col].shared3.prev = EMPTY ;
+        Col [col].shared4.degree_next = EMPTY ;
+    }
+
+    /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
+
+    /* === Scan columns, compute row degrees, and check row indices ========= */
+
+    stats [COLAMD_INFO3] = 0 ;  /* number of duplicate or unsorted row indices*/
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+        Row [row].length = 0 ;
+        Row [row].shared2.mark = -1 ;
+    }
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+        last_row = -1 ;
+
+        cp = &A [p [col]] ;
+        cp_end = &A [p [col+1]] ;
+
+        while (cp < cp_end)
+        {
+            row = *cp++ ;
+
+            /* make sure row indices within range */
+            if (row < 0 || row >= n_row)
+            {
+                stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+                stats [COLAMD_INFO1] = col ;
+                stats [COLAMD_INFO2] = row ;
+                stats [COLAMD_INFO3] = n_row ;
+                DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
+                return (FALSE) ;
+            }
+
+            if (row <= last_row || Row [row].shared2.mark == col)
+            {
+                /* row index are unsorted or repeated (or both), thus col */
+                /* is jumbled.  This is a notice, not an error condition. */
+                stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+                stats [COLAMD_INFO1] = col ;
+                stats [COLAMD_INFO2] = row ;
+                (stats [COLAMD_INFO3]) ++ ;
+                DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
+            }
+
+            if (Row [row].shared2.mark != col)
+            {
+                Row [row].length++ ;
+            }
+            else
+            {
+                /* this is a repeated entry in the column, */
+                /* it will be removed */
+                Col [col].length-- ;
+            }
+
+            /* mark the row as having been seen in this column */
+            Row [row].shared2.mark = col ;
+
+            last_row = row ;
+        }
+    }
+
+    /* === Compute row pointers ============================================= */
+
+    /* row form of the matrix starts directly after the column */
+    /* form of matrix in A */
+    Row [0].start = p [n_col] ;
+    Row [0].shared1.p = Row [0].start ;
+    Row [0].shared2.mark = -1 ;
+    for (row = 1 ; row < n_row ; row++)
+    {
+        Row [row].start = Row [row-1].start + Row [row-1].length ;
+        Row [row].shared1.p = Row [row].start ;
+        Row [row].shared2.mark = -1 ;
+    }
+
+    /* === Create row form ================================================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+        /* if cols jumbled, watch for repeated row indices */
+        for (col = 0 ; col < n_col ; col++)
+        {
+            cp = &A [p [col]] ;
+            cp_end = &A [p [col+1]] ;
+            while (cp < cp_end)
+            {
+                row = *cp++ ;
+                if (Row [row].shared2.mark != col)
+                {
+                    A [(Row [row].shared1.p)++] = col ;
+                    Row [row].shared2.mark = col ;
+                }
+            }
+        }
+    }
+    else
+    {
+        /* if cols not jumbled, we don't need the mark (this is faster) */
+        for (col = 0 ; col < n_col ; col++)
+        {
+            cp = &A [p [col]] ;
+            cp_end = &A [p [col+1]] ;
+            while (cp < cp_end)
+            {
+                A [(Row [*cp++].shared1.p)++] = col ;
+            }
+        }
+    }
+
+    /* === Clear the row marks and set row degrees ========================== */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+        Row [row].shared2.mark = 0 ;
+        Row [row].shared1.degree = Row [row].length ;
+    }
+
+    /* === See if we need to re-create columns ============================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+        DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
+
+#ifndef NDEBUG
+        /* make sure column lengths are correct */
+        for (col = 0 ; col < n_col ; col++)
+        {
+            p [col] = Col [col].length ;
+        }
+        for (row = 0 ; row < n_row ; row++)
+        {
+            rp = &A [Row [row].start] ;
+            rp_end = rp + Row [row].length ;
+            while (rp < rp_end)
+            {
+                p [*rp++]-- ;
+            }
+        }
+        for (col = 0 ; col < n_col ; col++)
+        {
+            ASSERT (p [col] == 0) ;
+        }
+        /* now p is all zero (different than when debugging is turned off) */
+#endif /* NDEBUG */
+
+        /* === Compute col pointers ========================================= */
+
+        /* col form of the matrix starts at A [0]. */
+        /* Note, we may have a gap between the col form and the row */
+        /* form if there were duplicate entries, if so, it will be */
+        /* removed upon the first garbage collection */
+        Col [0].start = 0 ;
+        p [0] = Col [0].start ;
+        for (col = 1 ; col < n_col ; col++)
+        {
+            /* note that the lengths here are for pruned columns, i.e. */
+            /* no duplicate row indices will exist for these columns */
+            Col [col].start = Col [col-1].start + Col [col-1].length ;
+            p [col] = Col [col].start ;
+        }
+
+        /* === Re-create col form =========================================== */
+
+        for (row = 0 ; row < n_row ; row++)
+        {
+            rp = &A [Row [row].start] ;
+            rp_end = rp + Row [row].length ;
+            while (rp < rp_end)
+            {
+                A [(p [*rp++])++] = row ;
+            }
+        }
+    }
+
+    /* === Done.  Matrix is not (or no longer) jumbled ====================== */
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === init_scoring ========================================================= */
+/* ========================================================================== */
+
+/*
+    Kills dense or empty columns and rows, calculates an initial score for
+    each column, and places all columns in the degree lists.  Not user-callable.
+*/
+
+PRIVATE void init_scoring
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                  /* number of rows of A */
+    Int n_col,                  /* number of columns of A */
+    Colamd_Row Row [],          /* of size n_row+1 */
+    Colamd_Col Col [],          /* of size n_col+1 */
+    Int A [],                   /* column form and row form of A */
+    Int head [],                /* of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameters */
+    Int *p_n_row2,              /* number of non-dense, non-empty rows */
+    Int *p_n_col2,              /* number of non-dense, non-empty columns */
+    Int *p_max_deg              /* maximum row degree */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int c ;                     /* a column index */
+    Int r, row ;                /* a row index */
+    Int *cp ;                   /* a column pointer */
+    Int deg ;                   /* degree of a row or column */
+    Int *cp_end ;               /* a pointer to the end of a column */
+    Int *new_cp ;               /* new column pointer */
+    Int col_length ;            /* length of pruned column */
+    Int score ;                 /* current column score */
+    Int n_col2 ;                /* number of non-dense, non-empty columns */
+    Int n_row2 ;                /* number of non-dense, non-empty rows */
+    Int dense_row_count ;       /* remove rows with more entries than this */
+    Int dense_col_count ;       /* remove cols with more entries than this */
+    Int min_score ;             /* smallest column score */
+    Int max_deg ;               /* maximum row degree */
+    Int next_col ;              /* Used to add to degree list.*/
+
+#ifndef NDEBUG
+    Int debug_count ;           /* debug only. */
+#endif /* NDEBUG */
+
+    /* === Extract knobs ==================================================== */
+
+    /* Note: if knobs contains a NaN, this is undefined: */
+    if (knobs [COLAMD_DENSE_ROW] < 0)
+    {
+        /* only remove completely dense rows */
+        dense_row_count = n_col-1 ;
+    }
+    else
+    {
+        dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
+    }
+    if (knobs [COLAMD_DENSE_COL] < 0)
+    {
+        /* only remove completely dense columns */
+        dense_col_count = n_row-1 ;
+    }
+    else
+    {
+        dense_col_count =
+            DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
+    }
+
+    DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
+    max_deg = 0 ;
+    n_col2 = n_col ;
+    n_row2 = n_row ;
+
+    /* === Kill empty columns =============================================== */
+
+    /* Put the empty columns at the end in their natural order, so that LU */
+    /* factorization can proceed as far as possible. */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+        deg = Col [c].length ;
+        if (deg == 0)
+        {
+            /* this is a empty column, kill and order it last */
+            Col [c].shared2.order = --n_col2 ;
+            KILL_PRINCIPAL_COL (c) ;
+        }
+    }
+    DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense columns =============================================== */
+
+    /* Put the dense columns at the end, in their natural order */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+        /* skip any dead columns */
+        if (COL_IS_DEAD (c))
+        {
+            continue ;
+        }
+        deg = Col [c].length ;
+        if (deg > dense_col_count)
+        {
+            /* this is a dense column, kill and order it last */
+            Col [c].shared2.order = --n_col2 ;
+            /* decrement the row degrees */
+            cp = &A [Col [c].start] ;
+            cp_end = cp + Col [c].length ;
+            while (cp < cp_end)
+            {
+                Row [*cp++].shared1.degree-- ;
+            }
+            KILL_PRINCIPAL_COL (c) ;
+        }
+    }
+    DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense and empty rows ======================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+        deg = Row [r].shared1.degree ;
+        ASSERT (deg >= 0 && deg <= n_col) ;
+        if (deg > dense_row_count || deg == 0)
+        {
+            /* kill a dense or empty row */
+            KILL_ROW (r) ;
+            --n_row2 ;
+        }
+        else
+        {
+            /* keep track of max degree of remaining rows */
+            max_deg = MAX (max_deg, deg) ;
+        }
+    }
+    DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
+
+    /* === Compute initial column scores ==================================== */
+
+    /* At this point the row degrees are accurate.  They reflect the number */
+    /* of "live" (non-dense) columns in each row.  No empty rows exist. */
+    /* Some "live" columns may contain only dead rows, however.  These are */
+    /* pruned in the code below. */
+
+    /* now find the initial matlab score for each column */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+        /* skip dead column */
+        if (COL_IS_DEAD (c))
+        {
+            continue ;
+        }
+        score = 0 ;
+        cp = &A [Col [c].start] ;
+        new_cp = cp ;
+        cp_end = cp + Col [c].length ;
+        while (cp < cp_end)
+        {
+            /* get a row */
+            row = *cp++ ;
+            /* skip if dead */
+            if (ROW_IS_DEAD (row))
+            {
+                continue ;
+            }
+            /* compact the column */
+            *new_cp++ = row ;
+            /* add row's external degree */
+            score += Row [row].shared1.degree - 1 ;
+            /* guard against integer overflow */
+            score = MIN (score, n_col) ;
+        }
+        /* determine pruned column length */
+        col_length = (Int) (new_cp - &A [Col [c].start]) ;
+        if (col_length == 0)
+        {
+            /* a newly-made null column (all rows in this col are "dense" */
+            /* and have already been killed) */
+            DEBUG2 (("Newly null killed: %d\n", c)) ;
+            Col [c].shared2.order = --n_col2 ;
+            KILL_PRINCIPAL_COL (c) ;
+        }
+        else
+        {
+            /* set column length and set score */
+            ASSERT (score >= 0) ;
+            ASSERT (score <= n_col) ;
+            Col [c].length = col_length ;
+            Col [c].shared2.score = score ;
+        }
+    }
+    DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
+        n_col-n_col2)) ;
+
+    /* At this point, all empty rows and columns are dead.  All live columns */
+    /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
+    /* yet).  Rows may contain dead columns, but all live rows contain at */
+    /* least one live column. */
+
+#ifndef NDEBUG
+    debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
+#endif /* NDEBUG */
+
+    /* === Initialize degree lists ========================================== */
+
+#ifndef NDEBUG
+    debug_count = 0 ;
+#endif /* NDEBUG */
+
+    /* clear the hash buckets */
+    for (c = 0 ; c <= n_col ; c++)
+    {
+        head [c] = EMPTY ;
+    }
+    min_score = n_col ;
+    /* place in reverse order, so low column indices are at the front */
+    /* of the lists.  This is to encourage natural tie-breaking */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+        /* only add principal columns to degree lists */
+        if (COL_IS_ALIVE (c))
+        {
+            DEBUG4 (("place %d score %d minscore %d ncol %d\n",
+                c, Col [c].shared2.score, min_score, n_col)) ;
+
+            /* === Add columns score to DList =============================== */
+
+            score = Col [c].shared2.score ;
+
+            ASSERT (min_score >= 0) ;
+            ASSERT (min_score <= n_col) ;
+            ASSERT (score >= 0) ;
+            ASSERT (score <= n_col) ;
+            ASSERT (head [score] >= EMPTY) ;
+
+            /* now add this column to dList at proper score location */
+            next_col = head [score] ;
+            Col [c].shared3.prev = EMPTY ;
+            Col [c].shared4.degree_next = next_col ;
+
+            /* if there already was a column with the same score, set its */
+            /* previous pointer to this new column */
+            if (next_col != EMPTY)
+            {
+                Col [next_col].shared3.prev = c ;
+            }
+            head [score] = c ;
+
+            /* see if this score is less than current min */
+            min_score = MIN (min_score, score) ;
+
+#ifndef NDEBUG
+            debug_count++ ;
+#endif /* NDEBUG */
+
+        }
+    }
+
+#ifndef NDEBUG
+    DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
+        debug_count, n_col, n_col-debug_count)) ;
+    ASSERT (debug_count == n_col2) ;
+    debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
+#endif /* NDEBUG */
+
+    /* === Return number of remaining columns, and max row degree =========== */
+
+    *p_n_col2 = n_col2 ;
+    *p_n_row2 = n_row2 ;
+    *p_max_deg = max_deg ;
+}
+
+
+/* ========================================================================== */
+/* === find_ordering ======================================================== */
+/* ========================================================================== */
+
+/*
+    Order the principal columns of the supercolumn form of the matrix
+    (no supercolumns on input).  Uses a minimum approximate column minimum
+    degree ordering method.  Not user-callable.
+*/
+
+PRIVATE Int find_ordering       /* return the number of garbage collections */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                  /* number of rows of A */
+    Int n_col,                  /* number of columns of A */
+    Int Alen,                   /* size of A, 2*nnz + n_col or larger */
+    Colamd_Row Row [],          /* of size n_row+1 */
+    Colamd_Col Col [],          /* of size n_col+1 */
+    Int A [],                   /* column form and row form of A */
+    Int head [],                /* of size n_col+1 */
+    Int n_col2,                 /* Remaining columns to order */
+    Int max_deg,                /* Maximum row degree */
+    Int pfree,                  /* index of first free slot (2*nnz on entry) */
+    Int aggressive
+)
+{
+    /* === Local variables ================================================== */
+
+    Int k ;                     /* current pivot ordering step */
+    Int pivot_col ;             /* current pivot column */
+    Int *cp ;                   /* a column pointer */
+    Int *rp ;                   /* a row pointer */
+    Int pivot_row ;             /* current pivot row */
+    Int *new_cp ;               /* modified column pointer */
+    Int *new_rp ;               /* modified row pointer */
+    Int pivot_row_start ;       /* pointer to start of pivot row */
+    Int pivot_row_degree ;      /* number of columns in pivot row */
+    Int pivot_row_length ;      /* number of supercolumns in pivot row */
+    Int pivot_col_score ;       /* score of pivot column */
+    Int needed_memory ;         /* free space needed for pivot row */
+    Int *cp_end ;               /* pointer to the end of a column */
+    Int *rp_end ;               /* pointer to the end of a row */
+    Int row ;                   /* a row index */
+    Int col ;                   /* a column index */
+    Int max_score ;             /* maximum possible score */
+    Int cur_score ;             /* score of current column */
+    unsigned Int hash ;         /* hash value for supernode detection */
+    Int head_column ;           /* head of hash bucket */
+    Int first_col ;             /* first column in hash bucket */
+    Int tag_mark ;              /* marker value for mark array */
+    Int row_mark ;              /* Row [row].shared2.mark */
+    Int set_difference ;        /* set difference size of row with pivot row */
+    Int min_score ;             /* smallest column score */
+    Int col_thickness ;         /* "thickness" (no. of columns in a supercol) */
+    Int max_mark ;              /* maximum value of tag_mark */
+    Int pivot_col_thickness ;   /* number of columns represented by pivot col */
+    Int prev_col ;              /* Used by Dlist operations. */
+    Int next_col ;              /* Used by Dlist operations. */
+    Int ngarbage ;              /* number of garbage collections performed */
+
+#ifndef NDEBUG
+    Int debug_d ;               /* debug loop counter */
+    Int debug_step = 0 ;        /* debug loop counter */
+#endif /* NDEBUG */
+
+    /* === Initialization and clear mark ==================================== */
+
+    max_mark = INT_MAX - n_col ;        /* INT_MAX defined in <limits.h> */
+    tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+    min_score = 0 ;
+    ngarbage = 0 ;
+    DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
+
+    /* === Order the columns ================================================ */
+
+    for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
+    {
+
+#ifndef NDEBUG
+        if (debug_step % 100 == 0)
+        {
+            DEBUG2 (("\n...       Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+        }
+        else
+        {
+            DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+        }
+        debug_step++ ;
+        debug_deg_lists (n_row, n_col, Row, Col, head,
+                min_score, n_col2-k, max_deg) ;
+        debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+
+        /* === Select pivot column, and order it ============================ */
+
+        /* make sure degree list isn't empty */
+        ASSERT (min_score >= 0) ;
+        ASSERT (min_score <= n_col) ;
+        ASSERT (head [min_score] >= EMPTY) ;
+
+#ifndef NDEBUG
+        for (debug_d = 0 ; debug_d < min_score ; debug_d++)
+        {
+            ASSERT (head [debug_d] == EMPTY) ;
+        }
+#endif /* NDEBUG */
+
+        /* get pivot column from head of minimum degree list */
+        while (head [min_score] == EMPTY && min_score < n_col)
+        {
+            min_score++ ;
+        }
+        pivot_col = head [min_score] ;
+        ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
+        next_col = Col [pivot_col].shared4.degree_next ;
+        head [min_score] = next_col ;
+        if (next_col != EMPTY)
+        {
+            Col [next_col].shared3.prev = EMPTY ;
+        }
+
+        ASSERT (COL_IS_ALIVE (pivot_col)) ;
+
+        /* remember score for defrag check */
+        pivot_col_score = Col [pivot_col].shared2.score ;
+
+        /* the pivot column is the kth column in the pivot order */
+        Col [pivot_col].shared2.order = k ;
+
+        /* increment order count by column thickness */
+        pivot_col_thickness = Col [pivot_col].shared1.thickness ;
+        k += pivot_col_thickness ;
+        ASSERT (pivot_col_thickness > 0) ;
+        DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
+
+        /* === Garbage_collection, if necessary ============================= */
+
+        needed_memory = MIN (pivot_col_score, n_col - k) ;
+        if (pfree + needed_memory >= Alen)
+        {
+            pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
+            ngarbage++ ;
+            /* after garbage collection we will have enough */
+            ASSERT (pfree + needed_memory < Alen) ;
+            /* garbage collection has wiped out the Row[].shared2.mark array */
+            tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+            debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+        }
+
+        /* === Compute pivot row pattern ==================================== */
+
+        /* get starting location for this new merged row */
+        pivot_row_start = pfree ;
+
+        /* initialize new row counts to zero */
+        pivot_row_degree = 0 ;
+
+        /* tag pivot column as having been visited so it isn't included */
+        /* in merged pivot row */
+        Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
+
+        /* pivot row is the union of all rows in the pivot column pattern */
+        cp = &A [Col [pivot_col].start] ;
+        cp_end = cp + Col [pivot_col].length ;
+        while (cp < cp_end)
+        {
+            /* get a row */
+            row = *cp++ ;
+            DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
+            /* skip if row is dead */
+            if (ROW_IS_ALIVE (row))
+            {
+                rp = &A [Row [row].start] ;
+                rp_end = rp + Row [row].length ;
+                while (rp < rp_end)
+                {
+                    /* get a column */
+                    col = *rp++ ;
+                    /* add the column, if alive and untagged */
+                    col_thickness = Col [col].shared1.thickness ;
+                    if (col_thickness > 0 && COL_IS_ALIVE (col))
+                    {
+                        /* tag column in pivot row */
+                        Col [col].shared1.thickness = -col_thickness ;
+                        ASSERT (pfree < Alen) ;
+                        /* place column in pivot row */
+                        A [pfree++] = col ;
+                        pivot_row_degree += col_thickness ;
+                    }
+                }
+            }
+        }
+
+        /* clear tag on pivot column */
+        Col [pivot_col].shared1.thickness = pivot_col_thickness ;
+        max_deg = MAX (max_deg, pivot_row_degree) ;
+
+#ifndef NDEBUG
+        DEBUG3 (("check2\n")) ;
+        debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+        /* === Kill all rows used to construct pivot row ==================== */
+
+        /* also kill pivot row, temporarily */
+        cp = &A [Col [pivot_col].start] ;
+        cp_end = cp + Col [pivot_col].length ;
+        while (cp < cp_end)
+        {
+            /* may be killing an already dead row */
+            row = *cp++ ;
+            DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
+            KILL_ROW (row) ;
+        }
+
+        /* === Select a row index to use as the new pivot row =============== */
+
+        pivot_row_length = pfree - pivot_row_start ;
+        if (pivot_row_length > 0)
+        {
+            /* pick the "pivot" row arbitrarily (first row in col) */
+            pivot_row = A [Col [pivot_col].start] ;
+            DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
+        }
+        else
+        {
+            /* there is no pivot row, since it is of zero length */
+            pivot_row = EMPTY ;
+            ASSERT (pivot_row_length == 0) ;
+        }
+        ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
+
+        /* === Approximate degree computation =============================== */
+
+        /* Here begins the computation of the approximate degree.  The column */
+        /* score is the sum of the pivot row "length", plus the size of the */
+        /* set differences of each row in the column minus the pattern of the */
+        /* pivot row itself.  The column ("thickness") itself is also */
+        /* excluded from the column score (we thus use an approximate */
+        /* external degree). */
+
+        /* The time taken by the following code (compute set differences, and */
+        /* add them up) is proportional to the size of the data structure */
+        /* being scanned - that is, the sum of the sizes of each column in */
+        /* the pivot row.  Thus, the amortized time to compute a column score */
+        /* is proportional to the size of that column (where size, in this */
+        /* context, is the column "length", or the number of row indices */
+        /* in that column).  The number of row indices in a column is */
+        /* monotonically non-decreasing, from the length of the original */
+        /* column on input to colamd. */
+
+        /* === Compute set differences ====================================== */
+
+        DEBUG3 (("** Computing set differences phase. **\n")) ;
+
+        /* pivot row is currently dead - it will be revived later. */
+
+        DEBUG3 (("Pivot row: ")) ;
+        /* for each column in pivot row */
+        rp = &A [pivot_row_start] ;
+        rp_end = rp + pivot_row_length ;
+        while (rp < rp_end)
+        {
+            col = *rp++ ;
+            ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+            DEBUG3 (("Col: %d\n", col)) ;
+
+            /* clear tags used to construct pivot row pattern */
+            col_thickness = -Col [col].shared1.thickness ;
+            ASSERT (col_thickness > 0) ;
+            Col [col].shared1.thickness = col_thickness ;
+
+            /* === Remove column from degree list =========================== */
+
+            cur_score = Col [col].shared2.score ;
+            prev_col = Col [col].shared3.prev ;
+            next_col = Col [col].shared4.degree_next ;
+            ASSERT (cur_score >= 0) ;
+            ASSERT (cur_score <= n_col) ;
+            ASSERT (cur_score >= EMPTY) ;
+            if (prev_col == EMPTY)
+            {
+                head [cur_score] = next_col ;
+            }
+            else
+            {
+                Col [prev_col].shared4.degree_next = next_col ;
+            }
+            if (next_col != EMPTY)
+            {
+                Col [next_col].shared3.prev = prev_col ;
+            }
+
+            /* === Scan the column ========================================== */
+
+            cp = &A [Col [col].start] ;
+            cp_end = cp + Col [col].length ;
+            while (cp < cp_end)
+            {
+                /* get a row */
+                row = *cp++ ;
+                row_mark = Row [row].shared2.mark ;
+                /* skip if dead */
+                if (ROW_IS_MARKED_DEAD (row_mark))
+                {
+                    continue ;
+                }
+                ASSERT (row != pivot_row) ;
+                set_difference = row_mark - tag_mark ;
+                /* check if the row has been seen yet */
+                if (set_difference < 0)
+                {
+                    ASSERT (Row [row].shared1.degree <= max_deg) ;
+                    set_difference = Row [row].shared1.degree ;
+                }
+                /* subtract column thickness from this row's set difference */
+                set_difference -= col_thickness ;
+                ASSERT (set_difference >= 0) ;
+                /* absorb this row if the set difference becomes zero */
+                if (set_difference == 0 && aggressive)
+                {
+                    DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
+                    KILL_ROW (row) ;
+                }
+                else
+                {
+                    /* save the new mark */
+                    Row [row].shared2.mark = set_difference + tag_mark ;
+                }
+            }
+        }
+
+#ifndef NDEBUG
+        debug_deg_lists (n_row, n_col, Row, Col, head,
+                min_score, n_col2-k-pivot_row_degree, max_deg) ;
+#endif /* NDEBUG */
+
+        /* === Add up set differences for each column ======================= */
+
+        DEBUG3 (("** Adding set differences phase. **\n")) ;
+
+        /* for each column in pivot row */
+        rp = &A [pivot_row_start] ;
+        rp_end = rp + pivot_row_length ;
+        while (rp < rp_end)
+        {
+            /* get a column */
+            col = *rp++ ;
+            ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+            hash = 0 ;
+            cur_score = 0 ;
+            cp = &A [Col [col].start] ;
+            /* compact the column */
+            new_cp = cp ;
+            cp_end = cp + Col [col].length ;
+
+            DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
+
+            while (cp < cp_end)
+            {
+                /* get a row */
+                row = *cp++ ;
+                ASSERT(row >= 0 && row < n_row) ;
+                row_mark = Row [row].shared2.mark ;
+                /* skip if dead */
+                if (ROW_IS_MARKED_DEAD (row_mark))
+                {
+                    DEBUG4 ((" Row %d, dead\n", row)) ;
+                    continue ;
+                }
+                DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
+                ASSERT (row_mark >= tag_mark) ;
+                /* compact the column */
+                *new_cp++ = row ;
+                /* compute hash function */
+                hash += row ;
+                /* add set difference */
+                cur_score += row_mark - tag_mark ;
+                /* integer overflow... */
+                cur_score = MIN (cur_score, n_col) ;
+            }
+
+            /* recompute the column's length */
+            Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
+
+            /* === Further mass elimination ================================= */
+
+            if (Col [col].length == 0)
+            {
+                DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
+                /* nothing left but the pivot row in this column */
+                KILL_PRINCIPAL_COL (col) ;
+                pivot_row_degree -= Col [col].shared1.thickness ;
+                ASSERT (pivot_row_degree >= 0) ;
+                /* order it */
+                Col [col].shared2.order = k ;
+                /* increment order count by column thickness */
+                k += Col [col].shared1.thickness ;
+            }
+            else
+            {
+                /* === Prepare for supercolumn detection ==================== */
+
+                DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
+
+                /* save score so far */
+                Col [col].shared2.score = cur_score ;
+
+                /* add column to hash table, for supercolumn detection */
+                hash %= n_col + 1 ;
+
+                DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
+                ASSERT (((Int) hash) <= n_col) ;
+
+                head_column = head [hash] ;
+                if (head_column > EMPTY)
+                {
+                    /* degree list "hash" is non-empty, use prev (shared3) of */
+                    /* first column in degree list as head of hash bucket */
+                    first_col = Col [head_column].shared3.headhash ;
+                    Col [head_column].shared3.headhash = col ;
+                }
+                else
+                {
+                    /* degree list "hash" is empty, use head as hash bucket */
+                    first_col = - (head_column + 2) ;
+                    head [hash] = - (col + 2) ;
+                }
+                Col [col].shared4.hash_next = first_col ;
+
+                /* save hash function in Col [col].shared3.hash */
+                Col [col].shared3.hash = (Int) hash ;
+                ASSERT (COL_IS_ALIVE (col)) ;
+            }
+        }
+
+        /* The approximate external column degree is now computed.  */
+
+        /* === Supercolumn detection ======================================== */
+
+        DEBUG3 (("** Supercolumn detection phase. **\n")) ;
+
+        detect_super_cols (
+
+#ifndef NDEBUG
+                n_col, Row,
+#endif /* NDEBUG */
+
+                Col, A, head, pivot_row_start, pivot_row_length) ;
+
+        /* === Kill the pivotal column ====================================== */
+
+        KILL_PRINCIPAL_COL (pivot_col) ;
+
+        /* === Clear mark =================================================== */
+
+        tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+        DEBUG3 (("check3\n")) ;
+        debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+        /* === Finalize the new pivot row, and column scores ================ */
+
+        DEBUG3 (("** Finalize scores phase. **\n")) ;
+
+        /* for each column in pivot row */
+        rp = &A [pivot_row_start] ;
+        /* compact the pivot row */
+        new_rp = rp ;
+        rp_end = rp + pivot_row_length ;
+        while (rp < rp_end)
+        {
+            col = *rp++ ;
+            /* skip dead columns */
+            if (COL_IS_DEAD (col))
+            {
+                continue ;
+            }
+            *new_rp++ = col ;
+            /* add new pivot row to column */
+            A [Col [col].start + (Col [col].length++)] = pivot_row ;
+
+            /* retrieve score so far and add on pivot row's degree. */
+            /* (we wait until here for this in case the pivot */
+            /* row's degree was reduced due to mass elimination). */
+            cur_score = Col [col].shared2.score + pivot_row_degree ;
+
+            /* calculate the max possible score as the number of */
+            /* external columns minus the 'k' value minus the */
+            /* columns thickness */
+            max_score = n_col - k - Col [col].shared1.thickness ;
+
+            /* make the score the external degree of the union-of-rows */
+            cur_score -= Col [col].shared1.thickness ;
+
+            /* make sure score is less or equal than the max score */
+            cur_score = MIN (cur_score, max_score) ;
+            ASSERT (cur_score >= 0) ;
+
+            /* store updated score */
+            Col [col].shared2.score = cur_score ;
+
+            /* === Place column back in degree list ========================= */
+
+            ASSERT (min_score >= 0) ;
+            ASSERT (min_score <= n_col) ;
+            ASSERT (cur_score >= 0) ;
+            ASSERT (cur_score <= n_col) ;
+            ASSERT (head [cur_score] >= EMPTY) ;
+            next_col = head [cur_score] ;
+            Col [col].shared4.degree_next = next_col ;
+            Col [col].shared3.prev = EMPTY ;
+            if (next_col != EMPTY)
+            {
+                Col [next_col].shared3.prev = col ;
+            }
+            head [cur_score] = col ;
+
+            /* see if this score is less than current min */
+            min_score = MIN (min_score, cur_score) ;
+
+        }
+
+#ifndef NDEBUG
+        debug_deg_lists (n_row, n_col, Row, Col, head,
+                min_score, n_col2-k, max_deg) ;
+#endif /* NDEBUG */
+
+        /* === Resurrect the new pivot row ================================== */
+
+        if (pivot_row_degree > 0)
+        {
+            /* update pivot row length to reflect any cols that were killed */
+            /* during super-col detection and mass elimination */
+            Row [pivot_row].start  = pivot_row_start ;
+            Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
+            ASSERT (Row [pivot_row].length > 0) ;
+            Row [pivot_row].shared1.degree = pivot_row_degree ;
+            Row [pivot_row].shared2.mark = 0 ;
+            /* pivot row is no longer dead */
+
+            DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
+                        pivot_row, pivot_row_degree)) ;
+        }
+    }
+
+    /* === All principal columns have now been ordered ====================== */
+
+    return (ngarbage) ;
+}
+
+
+/* ========================================================================== */
+/* === order_children ======================================================= */
+/* ========================================================================== */
+
+/*
+    The find_ordering routine has ordered all of the principal columns (the
+    representatives of the supercolumns).  The non-principal columns have not
+    yet been ordered.  This routine orders those columns by walking up the
+    parent tree (a column is a child of the column which absorbed it).  The
+    final permutation vector is then placed in p [0 ... n_col-1], with p [0]
+    being the first column, and p [n_col-1] being the last.  It doesn't look
+    like it at first glance, but be assured that this routine takes time linear
+    in the number of columns.  Although not immediately obvious, the time
+    taken by this routine is O (n_col), that is, linear in the number of
+    columns.  Not user-callable.
+*/
+
+PRIVATE void order_children
+(
+    /* === Parameters ======================================================= */
+
+    Int n_col,                  /* number of columns of A */
+    Colamd_Col Col [],          /* of size n_col+1 */
+    Int p []                    /* p [0 ... n_col-1] is the column permutation*/
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;                     /* loop counter for all columns */
+    Int c ;                     /* column index */
+    Int parent ;                /* index of column's parent */
+    Int order ;                 /* column's order */
+
+    /* === Order each non-principal column ================================== */
+
+    for (i = 0 ; i < n_col ; i++)
+    {
+        /* find an un-ordered non-principal column */
+        ASSERT (COL_IS_DEAD (i)) ;
+        if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
+        {
+            parent = i ;
+            /* once found, find its principal parent */
+            do
+            {
+                parent = Col [parent].shared1.parent ;
+            } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
+
+            /* now, order all un-ordered non-principal columns along path */
+            /* to this parent.  collapse tree at the same time */
+            c = i ;
+            /* get order of parent */
+            order = Col [parent].shared2.order ;
+
+            do
+            {
+                ASSERT (Col [c].shared2.order == EMPTY) ;
+
+                /* order this column */
+                Col [c].shared2.order = order++ ;
+                /* collaps tree */
+                Col [c].shared1.parent = parent ;
+
+                /* get immediate parent of this column */
+                c = Col [c].shared1.parent ;
+
+                /* continue until we hit an ordered column.  There are */
+                /* guarranteed not to be anymore unordered columns */
+                /* above an ordered column */
+            } while (Col [c].shared2.order == EMPTY) ;
+
+            /* re-order the super_col parent to largest order for this group */
+            Col [parent].shared2.order = order ;
+        }
+    }
+
+    /* === Generate the permutation ========================================= */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+        p [Col [c].shared2.order] = c ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === detect_super_cols ==================================================== */
+/* ========================================================================== */
+
+/*
+    Detects supercolumns by finding matches between columns in the hash buckets.
+    Check amongst columns in the set A [row_start ... row_start + row_length-1].
+    The columns under consideration are currently *not* in the degree lists,
+    and have already been placed in the hash buckets.
+
+    The hash bucket for columns whose hash function is equal to h is stored
+    as follows:
+
+        if head [h] is >= 0, then head [h] contains a degree list, so:
+
+                head [h] is the first column in degree bucket h.
+                Col [head [h]].headhash gives the first column in hash bucket h.
+
+        otherwise, the degree list is empty, and:
+
+                -(head [h] + 2) is the first column in hash bucket h.
+
+    For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
+    column" pointer.  Col [c].shared3.hash is used instead as the hash number
+    for that column.  The value of Col [c].shared4.hash_next is the next column
+    in the same hash bucket.
+
+    Assuming no, or "few" hash collisions, the time taken by this routine is
+    linear in the sum of the sizes (lengths) of each column whose score has
+    just been computed in the approximate degree computation.
+    Not user-callable.
+*/
+
+PRIVATE void detect_super_cols
+(
+    /* === Parameters ======================================================= */
+
+#ifndef NDEBUG
+    /* these two parameters are only needed when debugging is enabled: */
+    Int n_col,                  /* number of columns of A */
+    Colamd_Row Row [],          /* of size n_row+1 */
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],          /* of size n_col+1 */
+    Int A [],                   /* row indices of A */
+    Int head [],                /* head of degree lists and hash buckets */
+    Int row_start,              /* pointer to set of columns to check */
+    Int row_length              /* number of columns to check */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int hash ;                  /* hash value for a column */
+    Int *rp ;                   /* pointer to a row */
+    Int c ;                     /* a column index */
+    Int super_c ;               /* column index of the column to absorb into */
+    Int *cp1 ;                  /* column pointer for column super_c */
+    Int *cp2 ;                  /* column pointer for column c */
+    Int length ;                /* length of column super_c */
+    Int prev_c ;                /* column preceding c in hash bucket */
+    Int i ;                     /* loop counter */
+    Int *rp_end ;               /* pointer to the end of the row */
+    Int col ;                   /* a column index in the row to check */
+    Int head_column ;           /* first column in hash bucket or degree list */
+    Int first_col ;             /* first column in hash bucket */
+
+    /* === Consider each column in the row ================================== */
+
+    rp = &A [row_start] ;
+    rp_end = rp + row_length ;
+    while (rp < rp_end)
+    {
+        col = *rp++ ;
+        if (COL_IS_DEAD (col))
+        {
+            continue ;
+        }
+
+        /* get hash number for this column */
+        hash = Col [col].shared3.hash ;
+        ASSERT (hash <= n_col) ;
+
+        /* === Get the first column in this hash bucket ===================== */
+
+        head_column = head [hash] ;
+        if (head_column > EMPTY)
+        {
+            first_col = Col [head_column].shared3.headhash ;
+        }
+        else
+        {
+            first_col = - (head_column + 2) ;
+        }
+
+        /* === Consider each column in the hash bucket ====================== */
+
+        for (super_c = first_col ; super_c != EMPTY ;
+            super_c = Col [super_c].shared4.hash_next)
+        {
+            ASSERT (COL_IS_ALIVE (super_c)) ;
+            ASSERT (Col [super_c].shared3.hash == hash) ;
+            length = Col [super_c].length ;
+
+            /* prev_c is the column preceding column c in the hash bucket */
+            prev_c = super_c ;
+
+            /* === Compare super_c with all columns after it ================ */
+
+            for (c = Col [super_c].shared4.hash_next ;
+                 c != EMPTY ; c = Col [c].shared4.hash_next)
+            {
+                ASSERT (c != super_c) ;
+                ASSERT (COL_IS_ALIVE (c)) ;
+                ASSERT (Col [c].shared3.hash == hash) ;
+
+                /* not identical if lengths or scores are different */
+                if (Col [c].length != length ||
+                    Col [c].shared2.score != Col [super_c].shared2.score)
+                {
+                    prev_c = c ;
+                    continue ;
+                }
+
+                /* compare the two columns */
+                cp1 = &A [Col [super_c].start] ;
+                cp2 = &A [Col [c].start] ;
+
+                for (i = 0 ; i < length ; i++)
+                {
+                    /* the columns are "clean" (no dead rows) */
+                    ASSERT (ROW_IS_ALIVE (*cp1))  ;
+                    ASSERT (ROW_IS_ALIVE (*cp2))  ;
+                    /* row indices will same order for both supercols, */
+                    /* no gather scatter nessasary */
+                    if (*cp1++ != *cp2++)
+                    {
+                        break ;
+                    }
+                }
+
+                /* the two columns are different if the for-loop "broke" */
+                if (i != length)
+                {
+                    prev_c = c ;
+                    continue ;
+                }
+
+                /* === Got it!  two columns are identical =================== */
+
+                ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
+
+                Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
+                Col [c].shared1.parent = super_c ;
+                KILL_NON_PRINCIPAL_COL (c) ;
+                /* order c later, in order_children() */
+                Col [c].shared2.order = EMPTY ;
+                /* remove c from hash bucket */
+                Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
+            }
+        }
+
+        /* === Empty this hash bucket ======================================= */
+
+        if (head_column > EMPTY)
+        {
+            /* corresponding degree list "hash" is not empty */
+            Col [head_column].shared3.headhash = EMPTY ;
+        }
+        else
+        {
+            /* corresponding degree list "hash" is empty */
+            head [hash] = EMPTY ;
+        }
+    }
+}
+
+
+/* ========================================================================== */
+/* === garbage_collection =================================================== */
+/* ========================================================================== */
+
+/*
+    Defragments and compacts columns and rows in the workspace A.  Used when
+    all avaliable memory has been used while performing row merging.  Returns
+    the index of the first free position in A, after garbage collection.  The
+    time taken by this routine is linear is the size of the array A, which is
+    itself linear in the number of nonzeros in the input matrix.
+    Not user-callable.
+*/
+
+PRIVATE Int garbage_collection  /* returns the new value of pfree */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                  /* number of rows */
+    Int n_col,                  /* number of columns */
+    Colamd_Row Row [],          /* row info */
+    Colamd_Col Col [],          /* column info */
+    Int A [],                   /* A [0 ... Alen-1] holds the matrix */
+    Int *pfree                  /* &A [0] ... pfree is in use */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *psrc ;                 /* source pointer */
+    Int *pdest ;                /* destination pointer */
+    Int j ;                     /* counter */
+    Int r ;                     /* a row index */
+    Int c ;                     /* a column index */
+    Int length ;                /* length of a row or column */
+
+#ifndef NDEBUG
+    Int debug_rows ;
+    DEBUG2 (("Defrag..\n")) ;
+    for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
+    debug_rows = 0 ;
+#endif /* NDEBUG */
+
+    /* === Defragment the columns =========================================== */
+
+    pdest = &A[0] ;
+    for (c = 0 ; c < n_col ; c++)
+    {
+        if (COL_IS_ALIVE (c))
+        {
+            psrc = &A [Col [c].start] ;
+
+            /* move and compact the column */
+            ASSERT (pdest <= psrc) ;
+            Col [c].start = (Int) (pdest - &A [0]) ;
+            length = Col [c].length ;
+            for (j = 0 ; j < length ; j++)
+            {
+                r = *psrc++ ;
+                if (ROW_IS_ALIVE (r))
+                {
+                    *pdest++ = r ;
+                }
+            }
+            Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
+        }
+    }
+
+    /* === Prepare to defragment the rows =================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+        if (ROW_IS_DEAD (r) || (Row [r].length == 0))
+        {
+            /* This row is already dead, or is of zero length.  Cannot compact
+             * a row of zero length, so kill it.  NOTE: in the current version,
+             * there are no zero-length live rows.  Kill the row (for the first
+             * time, or again) just to be safe. */
+            KILL_ROW (r) ;
+        }
+        else
+        {
+            /* save first column index in Row [r].shared2.first_column */
+            psrc = &A [Row [r].start] ;
+            Row [r].shared2.first_column = *psrc ;
+            ASSERT (ROW_IS_ALIVE (r)) ;
+            /* flag the start of the row with the one's complement of row */
+            *psrc = ONES_COMPLEMENT (r) ;
+#ifndef NDEBUG
+            debug_rows++ ;
+#endif /* NDEBUG */
+        }
+    }
+
+    /* === Defragment the rows ============================================== */
+
+    psrc = pdest ;
+    while (psrc < pfree)
+    {
+        /* find a negative number ... the start of a row */
+        if (*psrc++ < 0)
+        {
+            psrc-- ;
+            /* get the row index */
+            r = ONES_COMPLEMENT (*psrc) ;
+            ASSERT (r >= 0 && r < n_row) ;
+            /* restore first column index */
+            *psrc = Row [r].shared2.first_column ;
+            ASSERT (ROW_IS_ALIVE (r)) ;
+            ASSERT (Row [r].length > 0) ;
+            /* move and compact the row */
+            ASSERT (pdest <= psrc) ;
+            Row [r].start = (Int) (pdest - &A [0]) ;
+            length = Row [r].length ;
+            for (j = 0 ; j < length ; j++)
+            {
+                c = *psrc++ ;
+                if (COL_IS_ALIVE (c))
+                {
+                    *pdest++ = c ;
+                }
+            }
+            Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
+            ASSERT (Row [r].length > 0) ;
+#ifndef NDEBUG
+            debug_rows-- ;
+#endif /* NDEBUG */
+        }
+    }
+    /* ensure we found all the rows */
+    ASSERT (debug_rows == 0) ;
+
+    /* === Return the new value of pfree ==================================== */
+
+    return ((Int) (pdest - &A [0])) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Clears the Row [].shared2.mark array, and returns the new tag_mark.
+    Return value is the new tag_mark.  Not user-callable.
+*/
+
+PRIVATE Int clear_mark  /* return the new value for tag_mark */
+(
+    /* === Parameters ======================================================= */
+
+    Int tag_mark,       /* new value of tag_mark */
+    Int max_mark,       /* max allowed value of tag_mark */
+
+    Int n_row,          /* number of rows in A */
+    Colamd_Row Row []   /* Row [0 ... n_row-1].shared2.mark is set to zero */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    if (tag_mark <= 0 || tag_mark >= max_mark)
+    {
+        for (r = 0 ; r < n_row ; r++)
+        {
+            if (ROW_IS_ALIVE (r))
+            {
+                Row [r].shared2.mark = 0 ;
+            }
+        }
+        tag_mark = 1 ;
+    }
+
+    return (tag_mark) ;
+}
+
+
+/* ========================================================================== */
+/* === print_report ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+)
+{
+
+    Int i1, i2, i3 ;
+
+    PRINTF (("\n%s version %d.%d, %s: ", method,
+            COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
+
+    if (!stats)
+    {
+        PRINTF (("No statistics available.\n")) ;
+        return ;
+    }
+
+    i1 = stats [COLAMD_INFO1] ;
+    i2 = stats [COLAMD_INFO2] ;
+    i3 = stats [COLAMD_INFO3] ;
+
+    if (stats [COLAMD_STATUS] >= 0)
+    {
+        PRINTF (("OK.  ")) ;
+    }
+    else
+    {
+        PRINTF (("ERROR.  ")) ;
+    }
+
+    switch (stats [COLAMD_STATUS])
+    {
+
+        case COLAMD_OK_BUT_JUMBLED:
+
+            PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
+
+            PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
+            method, i3)) ;
+
+            PRINTF(("%s: last seen duplicate or out-of-order row index:   %d\n",
+            method, INDEX (i2))) ;
+
+            PRINTF(("%s: last seen in column:                             %d",
+            method, INDEX (i1))) ;
+
+            /* no break - fall through to next case instead */
+
+        case COLAMD_OK:
+
+            PRINTF(("\n")) ;
+
+            PRINTF(("%s: number of dense or empty rows ignored:           %d\n",
+            method, stats [COLAMD_DENSE_ROW])) ;
+
+            PRINTF(("%s: number of dense or empty columns ignored:        %d\n",
+            method, stats [COLAMD_DENSE_COL])) ;
+
+            PRINTF(("%s: number of garbage collections performed:         %d\n",
+            method, stats [COLAMD_DEFRAG_COUNT])) ;
+            break ;
+
+        case COLAMD_ERROR_A_not_present:
+
+            PRINTF(("Array A (row indices of matrix) not present.\n")) ;
+            break ;
+
+        case COLAMD_ERROR_p_not_present:
+
+            PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
+            break ;
+
+        case COLAMD_ERROR_nrow_negative:
+
+            PRINTF(("Invalid number of rows (%d).\n", i1)) ;
+            break ;
+
+        case COLAMD_ERROR_ncol_negative:
+
+            PRINTF(("Invalid number of columns (%d).\n", i1)) ;
+            break ;
+
+        case COLAMD_ERROR_nnz_negative:
+
+            PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
+            break ;
+
+        case COLAMD_ERROR_p0_nonzero:
+
+            PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
+            break ;
+
+        case COLAMD_ERROR_A_too_small:
+
+            PRINTF(("Array A too small.\n")) ;
+            PRINTF(("        Need Alen >= %d, but given only Alen = %d.\n",
+            i1, i2)) ;
+            break ;
+
+        case COLAMD_ERROR_col_length_negative:
+
+            PRINTF
+            (("Column %d has a negative number of nonzero entries (%d).\n",
+            INDEX (i1), i2)) ;
+            break ;
+
+        case COLAMD_ERROR_row_index_out_of_bounds:
+
+            PRINTF
+            (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
+            INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
+            break ;
+
+        case COLAMD_ERROR_out_of_memory:
+
+            PRINTF(("Out of memory.\n")) ;
+            break ;
+
+        /* v2.4: internal-error case deleted */
+    }
+}
+
+
+
+
+/* ========================================================================== */
+/* === colamd debugging routines ============================================ */
+/* ========================================================================== */
+
+/* When debugging is disabled, the remainder of this file is ignored. */
+
+#ifndef NDEBUG
+
+
+/* ========================================================================== */
+/* === debug_structures ===================================================== */
+/* ========================================================================== */
+
+/*
+    At this point, all empty rows and columns are dead.  All live columns
+    are "clean" (containing no dead rows) and simplicial (no supercolumns
+    yet).  Rows may contain dead columns, but all live rows contain at
+    least one live column.
+*/
+
+PRIVATE void debug_structures
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+    Int c ;
+    Int *cp ;
+    Int *cp_end ;
+    Int len ;
+    Int score ;
+    Int r ;
+    Int *rp ;
+    Int *rp_end ;
+    Int deg ;
+
+    /* === Check A, Row, and Col ============================================ */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+        if (COL_IS_ALIVE (c))
+        {
+            len = Col [c].length ;
+            score = Col [c].shared2.score ;
+            DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
+            ASSERT (len > 0) ;
+            ASSERT (score >= 0) ;
+            ASSERT (Col [c].shared1.thickness == 1) ;
+            cp = &A [Col [c].start] ;
+            cp_end = cp + len ;
+            while (cp < cp_end)
+            {
+                r = *cp++ ;
+                ASSERT (ROW_IS_ALIVE (r)) ;
+            }
+        }
+        else
+        {
+            i = Col [c].shared2.order ;
+            ASSERT (i >= n_col2 && i < n_col) ;
+        }
+    }
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+        if (ROW_IS_ALIVE (r))
+        {
+            i = 0 ;
+            len = Row [r].length ;
+            deg = Row [r].shared1.degree ;
+            ASSERT (len > 0) ;
+            ASSERT (deg > 0) ;
+            rp = &A [Row [r].start] ;
+            rp_end = rp + len ;
+            while (rp < rp_end)
+            {
+                c = *rp++ ;
+                if (COL_IS_ALIVE (c))
+                {
+                    i++ ;
+                }
+            }
+            ASSERT (i > 0) ;
+        }
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_deg_lists ====================================================== */
+/* ========================================================================== */
+
+/*
+    Prints the contents of the degree lists.  Counts the number of columns
+    in the degree list and compares it to the total it should have.  Also
+    checks the row degrees.
+*/
+
+PRIVATE void debug_deg_lists
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+)
+{
+    /* === Local variables ================================================== */
+
+    Int deg ;
+    Int col ;
+    Int have ;
+    Int row ;
+
+    /* === Check the degree lists =========================================== */
+
+    if (n_col > 10000 && colamd_debug <= 0)
+    {
+        return ;
+    }
+    have = 0 ;
+    DEBUG4 (("Degree lists: %d\n", min_score)) ;
+    for (deg = 0 ; deg <= n_col ; deg++)
+    {
+        col = head [deg] ;
+        if (col == EMPTY)
+        {
+            continue ;
+        }
+        DEBUG4 (("%d:", deg)) ;
+        while (col != EMPTY)
+        {
+            DEBUG4 ((" %d", col)) ;
+            have += Col [col].shared1.thickness ;
+            ASSERT (COL_IS_ALIVE (col)) ;
+            col = Col [col].shared4.degree_next ;
+        }
+        DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("should %d have %d\n", should, have)) ;
+    ASSERT (should == have) ;
+
+    /* === Check the row degrees ============================================ */
+
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+        return ;
+    }
+    for (row = 0 ; row < n_row ; row++)
+    {
+        if (ROW_IS_ALIVE (row))
+        {
+            ASSERT (Row [row].shared1.degree <= max_deg) ;
+        }
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Ensures that the tag_mark is less that the maximum and also ensures that
+    each entry in the mark array is less than the tag mark.
+*/
+
+PRIVATE void debug_mark
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    /* === Check the Row marks ============================================== */
+
+    ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+        return ;
+    }
+    for (r = 0 ; r < n_row ; r++)
+    {
+        ASSERT (Row [r].shared2.mark < tag_mark) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_matrix ========================================================= */
+/* ========================================================================== */
+
+/*
+    Prints out the contents of the columns and the rows.
+*/
+
+PRIVATE void debug_matrix
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+    Int c ;
+    Int *rp ;
+    Int *rp_end ;
+    Int *cp ;
+    Int *cp_end ;
+
+    /* === Dump the rows and columns of the matrix ========================== */
+
+    if (colamd_debug < 3)
+    {
+        return ;
+    }
+    DEBUG3 (("DUMP MATRIX:\n")) ;
+    for (r = 0 ; r < n_row ; r++)
+    {
+        DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
+        if (ROW_IS_DEAD (r))
+        {
+            continue ;
+        }
+        DEBUG3 (("start %d length %d degree %d\n",
+                Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
+        rp = &A [Row [r].start] ;
+        rp_end = rp + Row [r].length ;
+        while (rp < rp_end)
+        {
+            c = *rp++ ;
+            DEBUG4 (("  %d col %d\n", COL_IS_ALIVE (c), c)) ;
+        }
+    }
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+        DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
+        if (COL_IS_DEAD (c))
+        {
+            continue ;
+        }
+        DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
+                Col [c].start, Col [c].length,
+                Col [c].shared1.thickness, Col [c].shared2.score)) ;
+        cp = &A [Col [c].start] ;
+        cp_end = cp + Col [c].length ;
+        while (cp < cp_end)
+        {
+            r = *cp++ ;
+            DEBUG4 (("  %d row %d\n", ROW_IS_ALIVE (r), r)) ;
+        }
+    }
+}
+
+PRIVATE void colamd_get_debug
+(
+    char *method
+)
+{
+    FILE *f ;
+    colamd_debug = 0 ;          /* no debug printing */
+    f = fopen ("debug", "r") ;
+    if (f == (FILE *) NULL)
+    {
+        colamd_debug = 0 ;
+    }
+    else
+    {
+        fscanf (f, "%d", &colamd_debug) ;
+        fclose (f) ;
+    }
+    DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
+        method, colamd_debug)) ;
+}
+
+#endif /* NDEBUG */
Index: deps/glpk/src/colamd/colamd.h
===================================================================
--- deps/glpk/src/colamd/colamd.h	(revision 9)
+++ deps/glpk/src/colamd/colamd.h	(revision 9)
@@ -0,0 +1,69 @@
+/* colamd.h */
+
+/* Written by Andrew Makhorin <mao@gnu.org>. */
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+
+#define COLAMD_DATE "Nov 1, 2007"
+#define COLAMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub))
+#define COLAMD_MAIN_VERSION 2
+#define COLAMD_SUB_VERSION 7
+#define COLAMD_SUBSUB_VERSION 1
+#define COLAMD_VERSION \
+        COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION)
+
+#define COLAMD_KNOBS 20
+#define COLAMD_STATS 20
+#define COLAMD_DENSE_ROW 0
+#define COLAMD_DENSE_COL 1
+#define COLAMD_AGGRESSIVE 2
+#define COLAMD_DEFRAG_COUNT 2
+#define COLAMD_STATUS 3
+#define COLAMD_INFO1 4
+#define COLAMD_INFO2 5
+#define COLAMD_INFO3 6
+
+#define COLAMD_OK                            (0)
+#define COLAMD_OK_BUT_JUMBLED                (1)
+#define COLAMD_ERROR_A_not_present           (-1)
+#define COLAMD_ERROR_p_not_present           (-2)
+#define COLAMD_ERROR_nrow_negative           (-3)
+#define COLAMD_ERROR_ncol_negative           (-4)
+#define COLAMD_ERROR_nnz_negative            (-5)
+#define COLAMD_ERROR_p0_nonzero              (-6)
+#define COLAMD_ERROR_A_too_small             (-7)
+#define COLAMD_ERROR_col_length_negative     (-8)
+#define COLAMD_ERROR_row_index_out_of_bounds (-9)
+#define COLAMD_ERROR_out_of_memory           (-10)
+#define COLAMD_ERROR_internal_error          (-999)
+
+#define colamd_recommended _glp_colamd_recommended
+size_t colamd_recommended(int nnz, int n_row, int n_col);
+
+#define colamd_set_defaults _glp_colamd_set_defaults
+void colamd_set_defaults(double knobs [COLAMD_KNOBS]);
+
+#define colamd _glp_colamd
+int colamd(int n_row, int n_col, int Alen, int A[], int p[],
+      double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS]);
+
+#define symamd _glp_symamd
+int symamd(int n, int A[], int p[], int perm[],
+      double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS],
+      void *(*allocate)(size_t, size_t), void(*release)(void *));
+
+#define colamd_report _glp_colamd_report
+void colamd_report(int stats[COLAMD_STATS]);
+
+#define symamd_report _glp_symamd_report
+void symamd_report(int stats[COLAMD_STATS]);
+
+#define colamd_printf xprintf
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpapi.h
===================================================================
--- deps/glpk/src/glpapi.h	(revision 9)
+++ deps/glpk/src/glpapi.h	(revision 9)
@@ -0,0 +1,314 @@
+/* glpapi.h (application program interface) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPAPI_H
+#define GLPAPI_H
+
+#define GLP_PROB_DEFINED
+typedef struct glp_prob glp_prob;
+
+#include "glpk.h"
+#include "glpavl.h"
+#include "glpbfd.h"
+
+typedef struct GLPROW GLPROW;
+typedef struct GLPCOL GLPCOL;
+typedef struct GLPAIJ GLPAIJ;
+
+#define GLP_PROB_MAGIC 0xD7D9D6C2
+
+struct glp_prob
+{     /* LP/MIP problem object */
+      unsigned magic;
+      /* magic value used for debugging */
+      DMP *pool;
+      /* memory pool to store problem object components */
+      glp_tree *tree;
+      /* pointer to the search tree; set by the MIP solver when this
+         object is used in the tree as a core MIP object */
+      void *parms;
+      /* reserved for backward compatibility */
+      /*--------------------------------------------------------------*/
+      /* LP/MIP data */
+      char *name;
+      /* problem name (1 to 255 chars); NULL means no name is assigned
+         to the problem */
+      char *obj;
+      /* objective function name (1 to 255 chars); NULL means no name
+         is assigned to the objective function */
+      int dir;
+      /* optimization direction flag (objective "sense"):
+         GLP_MIN - minimization
+         GLP_MAX - maximization */
+      double c0;
+      /* constant term of the objective function ("shift") */
+      int m_max;
+      /* length of the array of rows (enlarged automatically) */
+      int n_max;
+      /* length of the array of columns (enlarged automatically) */
+      int m;
+      /* number of rows, 0 <= m <= m_max */
+      int n;
+      /* number of columns, 0 <= n <= n_max */
+      int nnz;
+      /* number of non-zero constraint coefficients, nnz >= 0 */
+      GLPROW **row; /* GLPROW *row[1+m_max]; */
+      /* row[i], 1 <= i <= m, is a pointer to i-th row */
+      GLPCOL **col; /* GLPCOL *col[1+n_max]; */
+      /* col[j], 1 <= j <= n, is a pointer to j-th column */
+      AVL *r_tree;
+      /* row index to find rows by their names; NULL means this index
+         does not exist */
+      AVL *c_tree;
+      /* column index to find columns by their names; NULL means this
+         index does not exist */
+      /*--------------------------------------------------------------*/
+      /* basis factorization (LP) */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      int *head; /* int head[1+m_max]; */
+      /* basis header (valid only if the factorization is valid);
+         head[i] = k is the ordinal number of auxiliary (1 <= k <= m)
+         or structural (m+1 <= k <= m+n) variable which corresponds to
+         i-th basic variable xB[i], 1 <= i <= m */
+      glp_bfcp *bfcp;
+      /* basis factorization control parameters; may be NULL */
+      BFD *bfd; /* BFD bfd[1:m,1:m]; */
+      /* basis factorization driver; may be NULL */
+      /*--------------------------------------------------------------*/
+      /* basic solution (LP) */
+      int pbs_stat;
+      /* primal basic solution status:
+         GLP_UNDEF  - primal solution is undefined
+         GLP_FEAS   - primal solution is feasible
+         GLP_INFEAS - primal solution is infeasible
+         GLP_NOFEAS - no primal feasible solution exists */
+      int dbs_stat;
+      /* dual basic solution status:
+         GLP_UNDEF  - dual solution is undefined
+         GLP_FEAS   - dual solution is feasible
+         GLP_INFEAS - dual solution is infeasible
+         GLP_NOFEAS - no dual feasible solution exists */
+      double obj_val;
+      /* objective function value */
+      int it_cnt;
+      /* simplex method iteration count; increased by one on performing
+         one simplex iteration */
+      int some;
+      /* ordinal number of some auxiliary or structural variable having
+         certain property, 0 <= some <= m+n */
+      /*--------------------------------------------------------------*/
+      /* interior-point solution (LP) */
+      int ipt_stat;
+      /* interior-point solution status:
+         GLP_UNDEF  - interior solution is undefined
+         GLP_OPT    - interior solution is optimal
+         GLP_INFEAS - interior solution is infeasible
+         GLP_NOFEAS - no feasible solution exists */
+      double ipt_obj;
+      /* objective function value */
+      /*--------------------------------------------------------------*/
+      /* integer solution (MIP) */
+      int mip_stat;
+      /* integer solution status:
+         GLP_UNDEF  - integer solution is undefined
+         GLP_OPT    - integer solution is optimal
+         GLP_FEAS   - integer solution is feasible
+         GLP_NOFEAS - no integer solution exists */
+      double mip_obj;
+      /* objective function value */
+};
+
+struct GLPROW
+{     /* LP/MIP row (auxiliary variable) */
+      int i;
+      /* ordinal number (1 to m) assigned to this row */
+      char *name;
+      /* row name (1 to 255 chars); NULL means no name is assigned to
+         this row */
+      AVLNODE *node;
+      /* pointer to corresponding node in the row index; NULL means
+         that either the row index does not exist or this row has no
+         name assigned */
+#if 1 /* 20/IX-2008 */
+      int level;
+      unsigned char origin;
+      unsigned char klass;
+#endif
+      int type;
+      /* type of the auxiliary variable:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double lb; /* non-scaled */
+      /* lower bound; if the row has no lower bound, lb is zero */
+      double ub; /* non-scaled */
+      /* upper bound; if the row has no upper bound, ub is zero */
+      /* if the row type is GLP_FX, ub is equal to lb */
+      GLPAIJ *ptr; /* non-scaled */
+      /* pointer to doubly linked list of constraint coefficients which
+         are placed in this row */
+      double rii;
+      /* diagonal element r[i,i] of scaling matrix R for this row;
+         if the scaling is not used, r[i,i] is 1 */
+      int stat;
+      /* status of the auxiliary variable:
+         GLP_BS - basic variable
+         GLP_NL - non-basic variable on lower bound
+         GLP_NU - non-basic variable on upper bound
+         GLP_NF - non-basic free variable
+         GLP_NS - non-basic fixed variable */
+      int bind;
+      /* if the auxiliary variable is basic, head[bind] refers to this
+         row, otherwise, bind is 0; this attribute is valid only if the
+         basis factorization is valid */
+      double prim; /* non-scaled */
+      /* primal value of the auxiliary variable in basic solution */
+      double dual; /* non-scaled */
+      /* dual value of the auxiliary variable in basic solution */
+      double pval; /* non-scaled */
+      /* primal value of the auxiliary variable in interior solution */
+      double dval; /* non-scaled */
+      /* dual value of the auxiliary variable in interior solution */
+      double mipx; /* non-scaled */
+      /* primal value of the auxiliary variable in integer solution */
+};
+
+struct GLPCOL
+{     /* LP/MIP column (structural variable) */
+      int j;
+      /* ordinal number (1 to n) assigned to this column */
+      char *name;
+      /* column name (1 to 255 chars); NULL means no name is assigned
+         to this column */
+      AVLNODE *node;
+      /* pointer to corresponding node in the column index; NULL means
+         that either the column index does not exist or the column has
+         no name assigned */
+      int kind;
+      /* kind of the structural variable:
+         GLP_CV - continuous variable
+         GLP_IV - integer or binary variable */
+      int type;
+      /* type of the structural variable:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double lb; /* non-scaled */
+      /* lower bound; if the column has no lower bound, lb is zero */
+      double ub; /* non-scaled */
+      /* upper bound; if the column has no upper bound, ub is zero */
+      /* if the column type is GLP_FX, ub is equal to lb */
+      double coef; /* non-scaled */
+      /* objective coefficient at the structural variable */
+      GLPAIJ *ptr; /* non-scaled */
+      /* pointer to doubly linked list of constraint coefficients which
+         are placed in this column */
+      double sjj;
+      /* diagonal element s[j,j] of scaling matrix S for this column;
+         if the scaling is not used, s[j,j] is 1 */
+      int stat;
+      /* status of the structural variable:
+         GLP_BS - basic variable
+         GLP_NL - non-basic variable on lower bound
+         GLP_NU - non-basic variable on upper bound
+         GLP_NF - non-basic free variable
+         GLP_NS - non-basic fixed variable */
+      int bind;
+      /* if the structural variable is basic, head[bind] refers to
+         this column; otherwise, bind is 0; this attribute is valid only
+         if the basis factorization is valid */
+      double prim; /* non-scaled */
+      /* primal value of the structural variable in basic solution */
+      double dual; /* non-scaled */
+      /* dual value of the structural variable in basic solution */
+      double pval; /* non-scaled */
+      /* primal value of the structural variable in interior solution */
+      double dval; /* non-scaled */
+      /* dual value of the structural variable in interior solution */
+      double mipx; /* non-scaled */
+      /* primal value of the structural variable in integer solution */
+};
+
+struct GLPAIJ
+{     /* constraint coefficient a[i,j] */
+      GLPROW *row;
+      /* pointer to row, where this coefficient is placed */
+      GLPCOL *col;
+      /* pointer to column, where this coefficient is placed */
+      double val;
+      /* numeric (non-zero) value of this coefficient */
+      GLPAIJ *r_prev;
+      /* pointer to previous coefficient in the same row */
+      GLPAIJ *r_next;
+      /* pointer to next coefficient in the same row */
+      GLPAIJ *c_prev;
+      /* pointer to previous coefficient in the same column */
+      GLPAIJ *c_next;
+      /* pointer to next coefficient in the same column */
+};
+
+void _glp_check_kkt(glp_prob *P, int sol, int cond, double *ae_max,
+      int *ae_ind, double *re_max, int *re_ind);
+/* check feasibility and optimality conditions */
+
+#define lpx_put_solution _glp_put_solution
+void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
+      const int *d_stat, const double *obj_val, const int r_stat[],
+      const double r_prim[], const double r_dual[], const int c_stat[],
+      const double c_prim[], const double c_dual[]);
+/* store basic solution components */
+
+#define lpx_put_mip_soln _glp_put_mip_soln
+void lpx_put_mip_soln(LPX *lp, int i_stat, double row_mipx[],
+      double col_mipx[]);
+/* store mixed integer solution components */
+
+#if 1 /* 28/XI-2009 */
+int _glp_analyze_row(glp_prob *P, int len, const int ind[],
+      const double val[], int type, double rhs, double eps, int *_piv,
+      double *_x, double *_dx, double *_y, double *_dy, double *_dz);
+/* simulate one iteration of dual simplex method */
+#endif
+
+#if 1 /* 08/XII-2009 */
+void _glp_mpl_init_rand(glp_tran *tran, int seed);
+#endif
+
+#define glp_skpgen _glp_skpgen
+void glp_skpgen(int n, int r, int type, int v, int s, int a[],
+   int *b, int c[]);
+/* Pisinger's 0-1 single knapsack problem generator */
+
+#if 1 /* 28/V-2010 */
+int _glp_intopt1(glp_prob *P, const glp_iocp *parm);
+#endif
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpapi01.c
===================================================================
--- deps/glpk/src/glpapi01.c	(revision 9)
+++ deps/glpk/src/glpapi01.c	(revision 9)
@@ -0,0 +1,1570 @@
+/* glpapi01.c (problem creating and modifying routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal number of rows in the problem object */
+
+#define N_MAX 100000000 /* = 100*10^6 */
+/* maximal number of columns in the problem object */
+
+#define NNZ_MAX 500000000 /* = 500*10^6 */
+/* maximal number of constraint coefficients in the problem object */
+
+/***********************************************************************
+*  NAME
+*
+*  glp_create_prob - create problem object
+*
+*  SYNOPSIS
+*
+*  glp_prob *glp_create_prob(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_create_prob creates a new problem object, which is
+*  initially "empty", i.e. has no rows and columns.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the object created, which should be
+*  used in any subsequent operations on this object. */
+
+static void create_prob(glp_prob *lp)
+{     lp->magic = GLP_PROB_MAGIC;
+      lp->pool = dmp_create_pool();
+#if 0 /* 17/XI-2009 */
+      lp->cps = xmalloc(sizeof(struct LPXCPS));
+      lpx_reset_parms(lp);
+#else
+      lp->parms = NULL;
+#endif
+      lp->tree = NULL;
+#if 0
+      lp->lwa = 0;
+      lp->cwa = NULL;
+#endif
+      /* LP/MIP data */
+      lp->name = NULL;
+      lp->obj = NULL;
+      lp->dir = GLP_MIN;
+      lp->c0 = 0.0;
+      lp->m_max = 100;
+      lp->n_max = 200;
+      lp->m = lp->n = 0;
+      lp->nnz = 0;
+      lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
+      lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
+      lp->r_tree = lp->c_tree = NULL;
+      /* basis factorization */
+      lp->valid = 0;
+      lp->head = xcalloc(1+lp->m_max, sizeof(int));
+      lp->bfcp = NULL;
+      lp->bfd = NULL;
+      /* basic solution (LP) */
+      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+      lp->obj_val = 0.0;
+      lp->it_cnt = 0;
+      lp->some = 0;
+      /* interior-point solution (LP) */
+      lp->ipt_stat = GLP_UNDEF;
+      lp->ipt_obj = 0.0;
+      /* integer solution (MIP) */
+      lp->mip_stat = GLP_UNDEF;
+      lp->mip_obj = 0.0;
+      return;
+}
+
+glp_prob *glp_create_prob(void)
+{     glp_prob *lp;
+      lp = xmalloc(sizeof(glp_prob));
+      create_prob(lp);
+      return lp;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_prob_name - assign (change) problem name
+*
+*  SYNOPSIS
+*
+*  void glp_set_prob_name(glp_prob *lp, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_prob_name assigns a given symbolic name (1 up to
+*  255 characters) to the specified problem object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing symbolic name of the problem object. */
+
+void glp_set_prob_name(glp_prob *lp, const char *name)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_prob_name: operation not allowed\n");
+      if (lp->name != NULL)
+      {  dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1);
+         lp->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_prob_name: problem name too long\n");
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_prob_name: problem name contains invalid"
+                  " character(s)\n");
+         }
+         lp->name = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(lp->name, name);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_obj_name - assign (change) objective function name
+*
+*  SYNOPSIS
+*
+*  void glp_set_obj_name(glp_prob *lp, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_obj_name assigns a given symbolic name (1 up to
+*  255 characters) to the objective function of the specified problem
+*  object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing name of the objective function. */
+
+void glp_set_obj_name(glp_prob *lp, const char *name)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_obj_name: operation not allowed\n");
+     if (lp->obj != NULL)
+      {  dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1);
+         lp->obj = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_obj_name: objective name too long\n");
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_obj_name: objective name contains invali"
+                  "d character(s)\n");
+         }
+         lp->obj = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(lp->obj, name);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_obj_dir - set (change) optimization direction flag
+*
+*  SYNOPSIS
+*
+*  void glp_set_obj_dir(glp_prob *lp, int dir);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_obj_dir sets (changes) optimization direction
+*  flag (i.e. "sense" of the objective function) as specified by the
+*  parameter dir:
+*
+*  GLP_MIN - minimization;
+*  GLP_MAX - maximization. */
+
+void glp_set_obj_dir(glp_prob *lp, int dir)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_obj_dir: operation not allowed\n");
+     if (!(dir == GLP_MIN || dir == GLP_MAX))
+         xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n",
+            dir);
+      lp->dir = dir;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_rows - add new rows to problem object
+*
+*  SYNOPSIS
+*
+*  int glp_add_rows(glp_prob *lp, int nrs);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_rows adds nrs rows (constraints) to the specified
+*  problem object. New rows are always added to the end of the row list,
+*  so the ordinal numbers of existing rows remain unchanged.
+*
+*  Being added each new row is initially free (unbounded) and has empty
+*  list of the constraint coefficients.
+*
+*  RETURNS
+*
+*  The routine glp_add_rows returns the ordinal number of the first new
+*  row added to the problem object. */
+
+int glp_add_rows(glp_prob *lp, int nrs)
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      int m_new, i;
+      /* determine new number of rows */
+      if (nrs < 1)
+         xerror("glp_add_rows: nrs = %d; invalid number of rows\n",
+            nrs);
+      if (nrs > M_MAX - lp->m)
+         xerror("glp_add_rows: nrs = %d; too many rows\n", nrs);
+      m_new = lp->m + nrs;
+      /* increase the room, if necessary */
+      if (lp->m_max < m_new)
+      {  GLPROW **save = lp->row;
+         while (lp->m_max < m_new)
+         {  lp->m_max += lp->m_max;
+            xassert(lp->m_max > 0);
+         }
+         lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
+         memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *));
+         xfree(save);
+         /* do not forget about the basis header */
+         xfree(lp->head);
+         lp->head = xcalloc(1+lp->m_max, sizeof(int));
+      }
+      /* add new rows to the end of the row list */
+      for (i = lp->m+1; i <= m_new; i++)
+      {  /* create row descriptor */
+         lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW));
+         row->i = i;
+         row->name = NULL;
+         row->node = NULL;
+#if 1 /* 20/IX-2008 */
+         row->level = 0;
+         row->origin = 0;
+         row->klass = 0;
+         if (tree != NULL)
+         {  switch (tree->reason)
+            {  case 0:
+                  break;
+               case GLP_IROWGEN:
+                  xassert(tree->curr != NULL);
+                  row->level = tree->curr->level;
+                  row->origin = GLP_RF_LAZY;
+                  break;
+               case GLP_ICUTGEN:
+                  xassert(tree->curr != NULL);
+                  row->level = tree->curr->level;
+                  row->origin = GLP_RF_CUT;
+                  break;
+               default:
+                  xassert(tree != tree);
+            }
+         }
+#endif
+         row->type = GLP_FR;
+         row->lb = row->ub = 0.0;
+         row->ptr = NULL;
+         row->rii = 1.0;
+         row->stat = GLP_BS;
+#if 0
+         row->bind = -1;
+#else
+         row->bind = 0;
+#endif
+         row->prim = row->dual = 0.0;
+         row->pval = row->dval = 0.0;
+         row->mipx = 0.0;
+      }
+      /* set new number of rows */
+      lp->m = m_new;
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+#if 1
+      if (tree != NULL && tree->reason != 0) tree->reopt = 1;
+#endif
+      /* return the ordinal number of the first row added */
+      return m_new - nrs + 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_cols - add new columns to problem object
+*
+*  SYNOPSIS
+*
+*  int glp_add_cols(glp_prob *lp, int ncs);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_cols adds ncs columns (structural variables) to
+*  the specified problem object. New columns are always added to the end
+*  of the column list, so the ordinal numbers of existing columns remain
+*  unchanged.
+*
+*  Being added each new column is initially fixed at zero and has empty
+*  list of the constraint coefficients.
+*
+*  RETURNS
+*
+*  The routine glp_add_cols returns the ordinal number of the first new
+*  column added to the problem object. */
+
+int glp_add_cols(glp_prob *lp, int ncs)
+{     glp_tree *tree = lp->tree;
+      GLPCOL *col;
+      int n_new, j;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_add_cols: operation not allowed\n");
+      /* determine new number of columns */
+      if (ncs < 1)
+         xerror("glp_add_cols: ncs = %d; invalid number of columns\n",
+            ncs);
+      if (ncs > N_MAX - lp->n)
+         xerror("glp_add_cols: ncs = %d; too many columns\n", ncs);
+      n_new = lp->n + ncs;
+      /* increase the room, if necessary */
+      if (lp->n_max < n_new)
+      {  GLPCOL **save = lp->col;
+         while (lp->n_max < n_new)
+         {  lp->n_max += lp->n_max;
+            xassert(lp->n_max > 0);
+         }
+         lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
+         memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *));
+         xfree(save);
+      }
+      /* add new columns to the end of the column list */
+      for (j = lp->n+1; j <= n_new; j++)
+      {  /* create column descriptor */
+         lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL));
+         col->j = j;
+         col->name = NULL;
+         col->node = NULL;
+         col->kind = GLP_CV;
+         col->type = GLP_FX;
+         col->lb = col->ub = 0.0;
+         col->coef = 0.0;
+         col->ptr = NULL;
+         col->sjj = 1.0;
+         col->stat = GLP_NS;
+#if 0
+         col->bind = -1;
+#else
+         col->bind = 0; /* the basis may remain valid */
+#endif
+         col->prim = col->dual = 0.0;
+         col->pval = col->dval = 0.0;
+         col->mipx = 0.0;
+      }
+      /* set new number of columns */
+      lp->n = n_new;
+      /* return the ordinal number of the first column added */
+      return n_new - ncs + 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_row_name - assign (change) row name
+*
+*  SYNOPSIS
+*
+*  void glp_set_row_name(glp_prob *lp, int i, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_row_name assigns a given symbolic name (1 up to
+*  255 characters) to i-th row (auxiliary variable) of the specified
+*  problem object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing name of i-th row. */
+
+void glp_set_row_name(glp_prob *lp, int i, const char *name)
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_row_name: i = %d; row number out of range\n",
+            i);
+      row = lp->row[i];
+      if (tree != NULL && tree->reason != 0)
+      {  xassert(tree->curr != NULL);
+         xassert(row->level == tree->curr->level);
+      }
+      if (row->name != NULL)
+      {  if (row->node != NULL)
+         {  xassert(lp->r_tree != NULL);
+            avl_delete_node(lp->r_tree, row->node);
+            row->node = NULL;
+         }
+         dmp_free_atom(lp->pool, row->name, strlen(row->name)+1);
+         row->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_row_name: i = %d; row name too long\n",
+                  i);
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_row_name: i = %d: row name contains inva"
+                  "lid character(s)\n", i);
+         }
+         row->name = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(row->name, name);
+         if (lp->r_tree != NULL)
+         {  xassert(row->node == NULL);
+            row->node = avl_insert_node(lp->r_tree, row->name);
+            avl_set_node_link(row->node, row);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_name - assign (change) column name
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_name(glp_prob *lp, int j, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_name assigns a given symbolic name (1 up to
+*  255 characters) to j-th column (structural variable) of the specified
+*  problem object.
+*
+*  If the parameter name is NULL or empty string, the routine erases an
+*  existing name of j-th column. */
+
+void glp_set_col_name(glp_prob *lp, int j, const char *name)
+{     glp_tree *tree = lp->tree;
+      GLPCOL *col;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_col_name: operation not allowed\n");
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_col_name: j = %d; column number out of range\n"
+            , j);
+      col = lp->col[j];
+      if (col->name != NULL)
+      {  if (col->node != NULL)
+         {  xassert(lp->c_tree != NULL);
+            avl_delete_node(lp->c_tree, col->node);
+            col->node = NULL;
+         }
+         dmp_free_atom(lp->pool, col->name, strlen(col->name)+1);
+         col->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_col_name: j = %d; column name too long\n"
+                  , j);
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_col_name: j = %d: column name contains i"
+                  "nvalid character(s)\n", j);
+         }
+         col->name = dmp_get_atom(lp->pool, strlen(name)+1);
+         strcpy(col->name, name);
+         if (lp->c_tree != NULL && col->name != NULL)
+         {  xassert(col->node == NULL);
+            col->node = avl_insert_node(lp->c_tree, col->name);
+            avl_set_node_link(col->node, col);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_row_bnds - set (change) row bounds
+*
+*  SYNOPSIS
+*
+*  void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
+*     double ub);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_row_bnds sets (changes) the type and bounds of
+*  i-th row (auxiliary variable) of the specified problem object.
+*
+*  Parameters type, lb, and ub specify the type, lower bound, and upper
+*  bound, respectively, as follows:
+*
+*     Type           Bounds        Comments
+*     ------------------------------------------------------
+*     GLP_FR   -inf <  x <  +inf   Free variable
+*     GLP_LO     lb <= x <  +inf   Variable with lower bound
+*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
+*     GLP_DB     lb <= x <=  ub    Double-bounded variable
+*     GLP_FX           x  =  lb    Fixed variable
+*
+*  where x is the auxiliary variable associated with i-th row.
+*
+*  If the row has no lower bound, the parameter lb is ignored. If the
+*  row has no upper bound, the parameter ub is ignored. If the row is
+*  an equality constraint (i.e. the corresponding auxiliary variable is
+*  of fixed type), only the parameter lb is used while the parameter ub
+*  is ignored. */
+
+void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
+      double ub)
+{     GLPROW *row;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_row_bnds: i = %d; row number out of range\n",
+            i);
+      row = lp->row[i];
+      row->type = type;
+      switch (type)
+      {  case GLP_FR:
+            row->lb = row->ub = 0.0;
+            if (row->stat != GLP_BS) row->stat = GLP_NF;
+            break;
+         case GLP_LO:
+            row->lb = lb, row->ub = 0.0;
+            if (row->stat != GLP_BS) row->stat = GLP_NL;
+            break;
+         case GLP_UP:
+            row->lb = 0.0, row->ub = ub;
+            if (row->stat != GLP_BS) row->stat = GLP_NU;
+            break;
+         case GLP_DB:
+            row->lb = lb, row->ub = ub;
+            if (!(row->stat == GLP_BS ||
+                  row->stat == GLP_NL || row->stat == GLP_NU))
+               row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
+            break;
+         case GLP_FX:
+            row->lb = row->ub = lb;
+            if (row->stat != GLP_BS) row->stat = GLP_NS;
+            break;
+         default:
+            xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty"
+               "pe\n", i, type);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_bnds - set (change) column bounds
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
+*     double ub);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_bnds sets (changes) the type and bounds of
+*  j-th column (structural variable) of the specified problem object.
+*
+*  Parameters type, lb, and ub specify the type, lower bound, and upper
+*  bound, respectively, as follows:
+*
+*     Type           Bounds        Comments
+*     ------------------------------------------------------
+*     GLP_FR   -inf <  x <  +inf   Free variable
+*     GLP_LO     lb <= x <  +inf   Variable with lower bound
+*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
+*     GLP_DB     lb <= x <=  ub    Double-bounded variable
+*     GLP_FX           x  =  lb    Fixed variable
+*
+*  where x is the structural variable associated with j-th column.
+*
+*  If the column has no lower bound, the parameter lb is ignored. If the
+*  column has no upper bound, the parameter ub is ignored. If the column
+*  is of fixed type, only the parameter lb is used while the parameter
+*  ub is ignored. */
+
+void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
+      double ub)
+{     GLPCOL *col;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_col_bnds: j = %d; column number out of range\n"
+            , j);
+      col = lp->col[j];
+      col->type = type;
+      switch (type)
+      {  case GLP_FR:
+            col->lb = col->ub = 0.0;
+            if (col->stat != GLP_BS) col->stat = GLP_NF;
+            break;
+         case GLP_LO:
+            col->lb = lb, col->ub = 0.0;
+            if (col->stat != GLP_BS) col->stat = GLP_NL;
+            break;
+         case GLP_UP:
+            col->lb = 0.0, col->ub = ub;
+            if (col->stat != GLP_BS) col->stat = GLP_NU;
+            break;
+         case GLP_DB:
+            col->lb = lb, col->ub = ub;
+            if (!(col->stat == GLP_BS ||
+                  col->stat == GLP_NL || col->stat == GLP_NU))
+               col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
+            break;
+         case GLP_FX:
+            col->lb = col->ub = lb;
+            if (col->stat != GLP_BS) col->stat = GLP_NS;
+            break;
+         default:
+            xerror("glp_set_col_bnds: j = %d; type = %d; invalid column"
+               " type\n", j, type);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_obj_coef - set (change) obj. coefficient or constant term
+*
+*  SYNOPSIS
+*
+*  void glp_set_obj_coef(glp_prob *lp, int j, double coef);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_obj_coef sets (changes) objective coefficient at
+*  j-th column (structural variable) of the specified problem object.
+*
+*  If the parameter j is 0, the routine sets (changes) the constant term
+*  ("shift") of the objective function. */
+
+void glp_set_obj_coef(glp_prob *lp, int j, double coef)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_obj_coef: operation not allowed\n");
+      if (!(0 <= j && j <= lp->n))
+         xerror("glp_set_obj_coef: j = %d; column number out of range\n"
+            , j);
+      if (j == 0)
+         lp->c0 = coef;
+      else
+         lp->col[j]->coef = coef;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_mat_row - set (replace) row of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_mat_row stores (replaces) the contents of i-th
+*  row of the constraint matrix of the specified problem object.
+*
+*  Column indices and numeric values of new row elements must be placed
+*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
+*  0 <= len <= n is the new length of i-th row, n is the current number
+*  of columns in the problem object. Elements with identical column
+*  indices are not allowed. Zero elements are allowed, but they are not
+*  stored in the constraint matrix.
+*
+*  If the parameter len is zero, the parameters ind and/or val can be
+*  specified as NULL. */
+
+void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
+      const double val[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij, *next;
+      int j, k;
+      /* obtain pointer to i-th row */
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_mat_row: i = %d; row number out of range\n",
+            i);
+      row = lp->row[i];
+      if (tree != NULL && tree->reason != 0)
+      {  xassert(tree->curr != NULL);
+         xassert(row->level == tree->curr->level);
+      }
+      /* remove all existing elements from i-th row */
+      while (row->ptr != NULL)
+      {  /* take next element in the row */
+         aij = row->ptr;
+         /* remove the element from the row list */
+         row->ptr = aij->r_next;
+         /* obtain pointer to corresponding column */
+         col = aij->col;
+         /* remove the element from the column list */
+         if (aij->c_prev == NULL)
+            col->ptr = aij->c_next;
+         else
+            aij->c_prev->c_next = aij->c_next;
+         if (aij->c_next == NULL)
+            ;
+         else
+            aij->c_next->c_prev = aij->c_prev;
+         /* return the element to the memory pool */
+         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         /* if the corresponding column is basic, invalidate the basis
+            factorization */
+         if (col->stat == GLP_BS) lp->valid = 0;
+      }
+      /* store new contents of i-th row */
+      if (!(0 <= len && len <= lp->n))
+         xerror("glp_set_mat_row: i = %d; len = %d; invalid row length "
+            "\n", i, len);
+      if (len > NNZ_MAX - lp->nnz)
+         xerror("glp_set_mat_row: i = %d; len = %d; too many constraint"
+            " coefficients\n", i, len);
+      for (k = 1; k <= len; k++)
+      {  /* take number j of corresponding column */
+         j = ind[k];
+         /* obtain pointer to j-th column */
+         if (!(1 <= j && j <= lp->n))
+            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index"
+               " out of range\n", i, k, j);
+         col = lp->col[j];
+         /* if there is element with the same column index, it can only
+            be found in the beginning of j-th column list */
+         if (col->ptr != NULL && col->ptr->row->i == i)
+            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co"
+               "lumn indices not allowed\n", i, k, j);
+         /* create new element */
+         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+         aij->row = row;
+         aij->col = col;
+         aij->val = val[k];
+         /* add the new element to the beginning of i-th row and j-th
+            column lists */
+         aij->r_prev = NULL;
+         aij->r_next = row->ptr;
+         aij->c_prev = NULL;
+         aij->c_next = col->ptr;
+         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+         row->ptr = col->ptr = aij;
+         /* if the corresponding column is basic, invalidate the basis
+            factorization */
+         if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0;
+      }
+      /* remove zero elements from i-th row */
+      for (aij = row->ptr; aij != NULL; aij = next)
+      {  next = aij->r_next;
+         if (aij->val == 0.0)
+         {  /* remove the element from the row list */
+            if (aij->r_prev == NULL)
+               row->ptr = next;
+            else
+               aij->r_prev->r_next = next;
+            if (next == NULL)
+               ;
+            else
+               next->r_prev = aij->r_prev;
+            /* remove the element from the column list */
+            xassert(aij->c_prev == NULL);
+            aij->col->ptr = aij->c_next;
+            if (aij->c_next != NULL) aij->c_next->c_prev = NULL;
+            /* return the element to the memory pool */
+            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_mat_col - set (replace) column of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_mat_col stores (replaces) the contents of j-th
+*  column of the constraint matrix of the specified problem object.
+*
+*  Row indices and numeric values of new column elements must be placed
+*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
+*  0 <= len <= m is the new length of j-th column, m is the current
+*  number of rows in the problem object. Elements with identical column
+*  indices are not allowed. Zero elements are allowed, but they are not
+*  stored in the constraint matrix.
+*
+*  If the parameter len is zero, the parameters ind and/or val can be
+*  specified as NULL. */
+
+void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
+      const double val[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij, *next;
+      int i, k;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_set_mat_col: operation not allowed\n");
+      /* obtain pointer to j-th column */
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_mat_col: j = %d; column number out of range\n",
+            j);
+      col = lp->col[j];
+      /* remove all existing elements from j-th column */
+      while (col->ptr != NULL)
+      {  /* take next element in the column */
+         aij = col->ptr;
+         /* remove the element from the column list */
+         col->ptr = aij->c_next;
+         /* obtain pointer to corresponding row */
+         row = aij->row;
+         /* remove the element from the row list */
+         if (aij->r_prev == NULL)
+            row->ptr = aij->r_next;
+         else
+            aij->r_prev->r_next = aij->r_next;
+         if (aij->r_next == NULL)
+            ;
+         else
+            aij->r_next->r_prev = aij->r_prev;
+         /* return the element to the memory pool */
+         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+      }
+      /* store new contents of j-th column */
+      if (!(0 <= len && len <= lp->m))
+         xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng"
+            "th\n", j, len);
+      if (len > NNZ_MAX - lp->nnz)
+         xerror("glp_set_mat_col: j = %d; len = %d; too many constraint"
+            " coefficients\n", j, len);
+      for (k = 1; k <= len; k++)
+      {  /* take number i of corresponding row */
+         i = ind[k];
+         /* obtain pointer to i-th row */
+         if (!(1 <= i && i <= lp->m))
+            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou"
+               "t of range\n", j, k, i);
+         row = lp->row[i];
+         /* if there is element with the same row index, it can only be
+            found in the beginning of i-th row list */
+         if (row->ptr != NULL && row->ptr->col->j == j)
+            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro"
+               "w indices not allowed\n", j, k, i);
+         /* create new element */
+         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+         aij->row = row;
+         aij->col = col;
+         aij->val = val[k];
+         /* add the new element to the beginning of i-th row and j-th
+            column lists */
+         aij->r_prev = NULL;
+         aij->r_next = row->ptr;
+         aij->c_prev = NULL;
+         aij->c_next = col->ptr;
+         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+         row->ptr = col->ptr = aij;
+      }
+      /* remove zero elements from j-th column */
+      for (aij = col->ptr; aij != NULL; aij = next)
+      {  next = aij->c_next;
+         if (aij->val == 0.0)
+         {  /* remove the element from the row list */
+            xassert(aij->r_prev == NULL);
+            aij->row->ptr = aij->r_next;
+            if (aij->r_next != NULL) aij->r_next->r_prev = NULL;
+            /* remove the element from the column list */
+            if (aij->c_prev == NULL)
+               col->ptr = next;
+            else
+               aij->c_prev->c_next = next;
+            if (next == NULL)
+               ;
+            else
+               next->c_prev = aij->c_prev;
+            /* return the element to the memory pool */
+            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         }
+      }
+      /* if j-th column is basic, invalidate the basis factorization */
+      if (col->stat == GLP_BS) lp->valid = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_load_matrix - load (replace) the whole constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
+*     const int ja[], const double ar[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_load_matrix loads the constraint matrix passed in
+*  the arrays ia, ja, and ar into the specified problem object. Before
+*  loading the current contents of the constraint matrix is destroyed.
+*
+*  Constraint coefficients (elements of the constraint matrix) must be
+*  specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne,
+*  where ia[k] is the row index, ja[k] is the column index, ar[k] is a
+*  numeric value of corresponding constraint coefficient. The parameter
+*  ne specifies the total number of (non-zero) elements in the matrix
+*  to be loaded. Coefficients with identical indices are not allowed.
+*  Zero coefficients are allowed, however, they are not stored in the
+*  constraint matrix.
+*
+*  If the parameter ne is zero, the parameters ia, ja, and ar can be
+*  specified as NULL. */
+
+void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
+      const int ja[], const double ar[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij, *next;
+      int i, j, k;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_load_matrix: operation not allowed\n");
+      /* clear the constraint matrix */
+      for (i = 1; i <= lp->m; i++)
+      {  row = lp->row[i];
+         while (row->ptr != NULL)
+         {  aij = row->ptr;
+            row->ptr = aij->r_next;
+            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+         }
+      }
+      xassert(lp->nnz == 0);
+      for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL;
+      /* load the new contents of the constraint matrix and build its
+         row lists */
+      if (ne < 0)
+         xerror("glp_load_matrix: ne = %d; invalid number of constraint"
+            " coefficients\n", ne);
+      if (ne > NNZ_MAX)
+         xerror("glp_load_matrix: ne = %d; too many constraint coeffici"
+            "ents\n", ne);
+      for (k = 1; k <= ne; k++)
+      {  /* take indices of new element */
+         i = ia[k], j = ja[k];
+         /* obtain pointer to i-th row */
+         if (!(1 <= i && i <= lp->m))
+            xerror("glp_load_matrix: ia[%d] = %d; row index out of rang"
+               "e\n", k, i);
+         row = lp->row[i];
+         /* obtain pointer to j-th column */
+         if (!(1 <= j && j <= lp->n))
+            xerror("glp_load_matrix: ja[%d] = %d; column index out of r"
+               "ange\n", k, j);
+         col = lp->col[j];
+         /* create new element */
+         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
+         aij->row = row;
+         aij->col = col;
+         aij->val = ar[k];
+         /* add the new element to the beginning of i-th row list */
+         aij->r_prev = NULL;
+         aij->r_next = row->ptr;
+         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+         row->ptr = aij;
+      }
+      xassert(lp->nnz == ne);
+      /* build column lists of the constraint matrix and check elements
+         with identical indices */
+      for (i = 1; i <= lp->m; i++)
+      {  for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  /* obtain pointer to corresponding column */
+            col = aij->col;
+            /* if there is element with identical indices, it can only
+               be found in the beginning of j-th column list */
+            if (col->ptr != NULL && col->ptr->row->i == i)
+            {  for (k = 1; k <= ne; k++)
+                  if (ia[k] == i && ja[k] == col->j) break;
+               xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat"
+                  "e indices not allowed\n", k, i, k, col->j);
+            }
+            /* add the element to the beginning of j-th column list */
+            aij->c_prev = NULL;
+            aij->c_next = col->ptr;
+            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+            col->ptr = aij;
+         }
+      }
+      /* remove zero elements from the constraint matrix */
+      for (i = 1; i <= lp->m; i++)
+      {  row = lp->row[i];
+         for (aij = row->ptr; aij != NULL; aij = next)
+         {  next = aij->r_next;
+            if (aij->val == 0.0)
+            {  /* remove the element from the row list */
+               if (aij->r_prev == NULL)
+                  row->ptr = next;
+               else
+                  aij->r_prev->r_next = next;
+               if (next == NULL)
+                  ;
+               else
+                  next->r_prev = aij->r_prev;
+               /* remove the element from the column list */
+               if (aij->c_prev == NULL)
+                  aij->col->ptr = aij->c_next;
+               else
+                  aij->c_prev->c_next = aij->c_next;
+               if (aij->c_next == NULL)
+                  ;
+               else
+                  aij->c_next->c_prev = aij->c_prev;
+               /* return the element to the memory pool */
+               dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
+            }
+         }
+      }
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_check_dup - check for duplicate elements in sparse matrix
+*
+*  SYNOPSIS
+*
+*  int glp_check_dup(int m, int n, int ne, const int ia[],
+*     const int ja[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_check_dup checks for duplicate elements (that is,
+*  elements with identical indices) in a sparse matrix specified in the
+*  coordinate format.
+*
+*  The parameters m and n specifies, respectively, the number of rows
+*  and columns in the matrix, m >= 0, n >= 0.
+*
+*  The parameter ne specifies the number of (structurally) non-zero
+*  elements in the matrix, ne >= 0.
+*
+*  Elements of the matrix are specified as doublets (ia[k],ja[k]) for
+*  k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index.
+*
+*  The routine glp_check_dup can be used prior to a call to the routine
+*  glp_load_matrix to check that the constraint matrix to be loaded has
+*  no duplicate elements.
+*
+*  RETURNS
+*
+*  The routine glp_check_dup returns one of the following values:
+*
+*   0 - the matrix has no duplicate elements;
+*
+*  -k - indices ia[k] or/and ja[k] are out of range;
+*
+*  +k - element (ia[k],ja[k]) is duplicate. */
+
+int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[])
+{     int i, j, k, *ptr, *next, ret;
+      char *flag;
+      if (m < 0)
+         xerror("glp_check_dup: m = %d; invalid parameter\n");
+      if (n < 0)
+         xerror("glp_check_dup: n = %d; invalid parameter\n");
+      if (ne < 0)
+         xerror("glp_check_dup: ne = %d; invalid parameter\n");
+      if (ne > 0 && ia == NULL)
+         xerror("glp_check_dup: ia = %p; invalid parameter\n", ia);
+      if (ne > 0 && ja == NULL)
+         xerror("glp_check_dup: ja = %p; invalid parameter\n", ja);
+      for (k = 1; k <= ne; k++)
+      {  i = ia[k], j = ja[k];
+         if (!(1 <= i && i <= m && 1 <= j && j <= n))
+         {  ret = -k;
+            goto done;
+         }
+      }
+      if (m == 0 || n == 0)
+      {  ret = 0;
+         goto done;
+      }
+      /* allocate working arrays */
+      ptr = xcalloc(1+m, sizeof(int));
+      next = xcalloc(1+ne, sizeof(int));
+      flag = xcalloc(1+n, sizeof(char));
+      /* build row lists */
+      for (i = 1; i <= m; i++)
+         ptr[i] = 0;
+      for (k = 1; k <= ne; k++)
+      {  i = ia[k];
+         next[k] = ptr[i];
+         ptr[i] = k;
+      }
+      /* clear column flags */
+      for (j = 1; j <= n; j++)
+         flag[j] = 0;
+      /* check for duplicate elements */
+      for (i = 1; i <= m; i++)
+      {  for (k = ptr[i]; k != 0; k = next[k])
+         {  j = ja[k];
+            if (flag[j])
+            {  /* find first element (i,j) */
+               for (k = 1; k <= ne; k++)
+                  if (ia[k] == i && ja[k] == j) break;
+               xassert(k <= ne);
+               /* find next (duplicate) element (i,j) */
+               for (k++; k <= ne; k++)
+                  if (ia[k] == i && ja[k] == j) break;
+               xassert(k <= ne);
+               ret = +k;
+               goto skip;
+            }
+            flag[j] = 1;
+         }
+         /* clear column flags */
+         for (k = ptr[i]; k != 0; k = next[k])
+            flag[ja[k]] = 0;
+      }
+      /* no duplicate element found */
+      ret = 0;
+skip: /* free working arrays */
+      xfree(ptr);
+      xfree(next);
+      xfree(flag);
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_sort_matrix - sort elements of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  void glp_sort_matrix(glp_prob *P);
+*
+*  DESCRIPTION
+*
+*  The routine glp_sort_matrix sorts elements of the constraint matrix
+*  rebuilding its row and column linked lists. On exit from the routine
+*  the constraint matrix is not changed, however, elements in the row
+*  linked lists become ordered by ascending column indices, and the
+*  elements in the column linked lists become ordered by ascending row
+*  indices. */
+
+void glp_sort_matrix(glp_prob *P)
+{     GLPAIJ *aij;
+      int i, j;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_sort_matrix: P = %p; invalid problem object\n",
+            P);
+      /* rebuild row linked lists */
+      for (i = P->m; i >= 1; i--)
+         P->row[i]->ptr = NULL;
+      for (j = P->n; j >= 1; j--)
+      {  for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next)
+         {  i = aij->row->i;
+            aij->r_prev = NULL;
+            aij->r_next = P->row[i]->ptr;
+            if (aij->r_next != NULL) aij->r_next->r_prev = aij;
+            P->row[i]->ptr = aij;
+         }
+      }
+      /* rebuild column linked lists */
+      for (j = P->n; j >= 1; j--)
+         P->col[j]->ptr = NULL;
+      for (i = P->m; i >= 1; i--)
+      {  for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  j = aij->col->j;
+            aij->c_prev = NULL;
+            aij->c_next = P->col[j]->ptr;
+            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
+            P->col[j]->ptr = aij;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_rows - delete rows from problem object
+*
+*  SYNOPSIS
+*
+*  void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_rows deletes rows from the specified problem
+*  object. Ordinal numbers of rows to be deleted should be placed in
+*  locations num[1], ..., num[nrs], where nrs > 0.
+*
+*  Note that deleting rows involves changing ordinal numbers of other
+*  rows remaining in the problem object. New ordinal numbers of the
+*  remaining rows are assigned under the assumption that the original
+*  order of rows is not changed. */
+
+void glp_del_rows(glp_prob *lp, int nrs, const int num[])
+{     glp_tree *tree = lp->tree;
+      GLPROW *row;
+      int i, k, m_new;
+      /* mark rows to be deleted */
+      if (!(1 <= nrs && nrs <= lp->m))
+         xerror("glp_del_rows: nrs = %d; invalid number of rows\n",
+            nrs);
+      for (k = 1; k <= nrs; k++)
+      {  /* take the number of row to be deleted */
+         i = num[k];
+         /* obtain pointer to i-th row */
+         if (!(1 <= i && i <= lp->m))
+            xerror("glp_del_rows: num[%d] = %d; row number out of range"
+               "\n", k, i);
+         row = lp->row[i];
+         if (tree != NULL && tree->reason != 0)
+         {  if (!(tree->reason == GLP_IROWGEN ||
+                  tree->reason == GLP_ICUTGEN))
+               xerror("glp_del_rows: operation not allowed\n");
+            xassert(tree->curr != NULL);
+            if (row->level != tree->curr->level)
+               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
+                  "elete row created not in current subproblem\n", k,i);
+            if (row->stat != GLP_BS)
+               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
+                  "elete active row (constraint)\n", k, i);
+            tree->reinv = 1;
+         }
+         /* check that the row is not marked yet */
+         if (row->i == 0)
+            xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n"
+               "ot allowed\n", k, i);
+         /* erase symbolic name assigned to the row */
+         glp_set_row_name(lp, i, NULL);
+         xassert(row->node == NULL);
+         /* erase corresponding row of the constraint matrix */
+         glp_set_mat_row(lp, i, 0, NULL, NULL);
+         xassert(row->ptr == NULL);
+         /* mark the row to be deleted */
+         row->i = 0;
+      }
+      /* delete all marked rows from the row list */
+      m_new = 0;
+      for (i = 1; i <= lp->m; i++)
+      {  /* obtain pointer to i-th row */
+         row = lp->row[i];
+         /* check if the row is marked */
+         if (row->i == 0)
+         {  /* it is marked, delete it */
+            dmp_free_atom(lp->pool, row, sizeof(GLPROW));
+         }
+         else
+         {  /* it is not marked; keep it */
+            row->i = ++m_new;
+            lp->row[row->i] = row;
+         }
+      }
+      /* set new number of rows */
+      lp->m = m_new;
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_cols - delete columns from problem object
+*
+*  SYNOPSIS
+*
+*  void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_cols deletes columns from the specified problem
+*  object. Ordinal numbers of columns to be deleted should be placed in
+*  locations num[1], ..., num[ncs], where ncs > 0.
+*
+*  Note that deleting columns involves changing ordinal numbers of
+*  other columns remaining in the problem object. New ordinal numbers
+*  of the remaining columns are assigned under the assumption that the
+*  original order of columns is not changed. */
+
+void glp_del_cols(glp_prob *lp, int ncs, const int num[])
+{     glp_tree *tree = lp->tree;
+      GLPCOL *col;
+      int j, k, n_new;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_del_cols: operation not allowed\n");
+      /* mark columns to be deleted */
+      if (!(1 <= ncs && ncs <= lp->n))
+         xerror("glp_del_cols: ncs = %d; invalid number of columns\n",
+            ncs);
+      for (k = 1; k <= ncs; k++)
+      {  /* take the number of column to be deleted */
+         j = num[k];
+         /* obtain pointer to j-th column */
+         if (!(1 <= j && j <= lp->n))
+            xerror("glp_del_cols: num[%d] = %d; column number out of ra"
+               "nge", k, j);
+         col = lp->col[j];
+         /* check that the column is not marked yet */
+         if (col->j == 0)
+            xerror("glp_del_cols: num[%d] = %d; duplicate column number"
+               "s not allowed\n", k, j);
+         /* erase symbolic name assigned to the column */
+         glp_set_col_name(lp, j, NULL);
+         xassert(col->node == NULL);
+         /* erase corresponding column of the constraint matrix */
+         glp_set_mat_col(lp, j, 0, NULL, NULL);
+         xassert(col->ptr == NULL);
+         /* mark the column to be deleted */
+         col->j = 0;
+         /* if it is basic, invalidate the basis factorization */
+         if (col->stat == GLP_BS) lp->valid = 0;
+      }
+      /* delete all marked columns from the column list */
+      n_new = 0;
+      for (j = 1; j <= lp->n; j++)
+      {  /* obtain pointer to j-th column */
+         col = lp->col[j];
+         /* check if the column is marked */
+         if (col->j == 0)
+         {  /* it is marked; delete it */
+            dmp_free_atom(lp->pool, col, sizeof(GLPCOL));
+         }
+         else
+         {  /* it is not marked; keep it */
+            col->j = ++n_new;
+            lp->col[col->j] = col;
+         }
+      }
+      /* set new number of columns */
+      lp->n = n_new;
+      /* if the basis header is still valid, adjust it */
+      if (lp->valid)
+      {  int m = lp->m;
+         int *head = lp->head;
+         for (j = 1; j <= n_new; j++)
+         {  k = lp->col[j]->bind;
+            if (k != 0)
+            {  xassert(1 <= k && k <= m);
+               head[k] = m + j;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_copy_prob - copy problem object content
+*
+*  SYNOPSIS
+*
+*  void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
+*
+*  DESCRIPTION
+*
+*  The routine glp_copy_prob copies the content of the problem object
+*  prob to the problem object dest.
+*
+*  The parameter names is a flag. If it is non-zero, the routine also
+*  copies all symbolic names; otherwise, if it is zero, symbolic names
+*  are not copied. */
+
+void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names)
+{     glp_tree *tree = dest->tree;
+      glp_bfcp bfcp;
+      int i, j, len, *ind;
+      double *val;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_copy_prob: operation not allowed\n");
+      if (dest == prob)
+         xerror("glp_copy_prob: copying problem object to itself not al"
+            "lowed\n");
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_copy_prob: names = %d; invalid parameter\n",
+            names);
+      glp_erase_prob(dest);
+      if (names && prob->name != NULL)
+         glp_set_prob_name(dest, prob->name);
+      if (names && prob->obj != NULL)
+         glp_set_obj_name(dest, prob->obj);
+      dest->dir = prob->dir;
+      dest->c0 = prob->c0;
+      if (prob->m > 0)
+         glp_add_rows(dest, prob->m);
+      if (prob->n > 0)
+         glp_add_cols(dest, prob->n);
+      glp_get_bfcp(prob, &bfcp);
+      glp_set_bfcp(dest, &bfcp);
+      dest->pbs_stat = prob->pbs_stat;
+      dest->dbs_stat = prob->dbs_stat;
+      dest->obj_val = prob->obj_val;
+      dest->some = prob->some;
+      dest->ipt_stat = prob->ipt_stat;
+      dest->ipt_obj = prob->ipt_obj;
+      dest->mip_stat = prob->mip_stat;
+      dest->mip_obj = prob->mip_obj;
+      for (i = 1; i <= prob->m; i++)
+      {  GLPROW *to = dest->row[i];
+         GLPROW *from = prob->row[i];
+         if (names && from->name != NULL)
+            glp_set_row_name(dest, i, from->name);
+         to->type = from->type;
+         to->lb = from->lb;
+         to->ub = from->ub;
+         to->rii = from->rii;
+         to->stat = from->stat;
+         to->prim = from->prim;
+         to->dual = from->dual;
+         to->pval = from->pval;
+         to->dval = from->dval;
+         to->mipx = from->mipx;
+      }
+      ind = xcalloc(1+prob->m, sizeof(int));
+      val = xcalloc(1+prob->m, sizeof(double));
+      for (j = 1; j <= prob->n; j++)
+      {  GLPCOL *to = dest->col[j];
+         GLPCOL *from = prob->col[j];
+         if (names && from->name != NULL)
+            glp_set_col_name(dest, j, from->name);
+         to->kind = from->kind;
+         to->type = from->type;
+         to->lb = from->lb;
+         to->ub = from->ub;
+         to->coef = from->coef;
+         len = glp_get_mat_col(prob, j, ind, val);
+         glp_set_mat_col(dest, j, len, ind, val);
+         to->sjj = from->sjj;
+         to->stat = from->stat;
+         to->prim = from->prim;
+         to->dual = from->dual;
+         to->pval = from->pval;
+         to->dval = from->dval;
+         to->mipx = from->mipx;
+      }
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_erase_prob - erase problem object content
+*
+*  SYNOPSIS
+*
+*  void glp_erase_prob(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_erase_prob erases the content of the specified
+*  problem object. The effect of this operation is the same as if the
+*  problem object would be deleted with the routine glp_delete_prob and
+*  then created anew with the routine glp_create_prob, with exception
+*  that the handle (pointer) to the problem object remains valid. */
+
+static void delete_prob(glp_prob *lp);
+
+void glp_erase_prob(glp_prob *lp)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_erase_prob: operation not allowed\n");
+      delete_prob(lp);
+      create_prob(lp);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_delete_prob - delete problem object
+*
+*  SYNOPSIS
+*
+*  void glp_delete_prob(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_delete_prob deletes the specified problem object and
+*  frees all the memory allocated to it. */
+
+static void delete_prob(glp_prob *lp)
+{     lp->magic = 0x3F3F3F3F;
+      dmp_delete_pool(lp->pool);
+#if 0 /* 17/XI-2009 */
+      xfree(lp->cps);
+#else
+      if (lp->parms != NULL) xfree(lp->parms);
+#endif
+      xassert(lp->tree == NULL);
+#if 0
+      if (lp->cwa != NULL) xfree(lp->cwa);
+#endif
+      xfree(lp->row);
+      xfree(lp->col);
+      if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree);
+      if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree);
+      xfree(lp->head);
+      if (lp->bfcp != NULL) xfree(lp->bfcp);
+      if (lp->bfd != NULL) bfd_delete_it(lp->bfd);
+      return;
+}
+
+void glp_delete_prob(glp_prob *lp)
+{     glp_tree *tree = lp->tree;
+      if (tree != NULL && tree->reason != 0)
+         xerror("glp_delete_prob: operation not allowed\n");
+      delete_prob(lp);
+      xfree(lp);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi02.c
===================================================================
--- deps/glpk/src/glpapi02.c	(revision 9)
+++ deps/glpk/src/glpapi02.c	(revision 9)
@@ -0,0 +1,491 @@
+/* glpapi02.c (problem retrieving routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_prob_name - retrieve problem name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_prob_name(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_prob_name returns a pointer to an internal
+*  buffer, which contains symbolic name of the problem. However, if the
+*  problem has no assigned name, the routine returns NULL. */
+
+const char *glp_get_prob_name(glp_prob *lp)
+{     char *name;
+      name = lp->name;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_name - retrieve objective function name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_obj_name(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_name returns a pointer to an internal
+*  buffer, which contains a symbolic name of the objective function.
+*  However, if the objective function has no assigned name, the routine
+*  returns NULL. */
+
+const char *glp_get_obj_name(glp_prob *lp)
+{     char *name;
+      name = lp->obj;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_dir - retrieve optimization direction flag
+*
+*  SYNOPSIS
+*
+*  int glp_get_obj_dir(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_dir returns the optimization direction flag
+*  (i.e. "sense" of the objective function):
+*
+*  GLP_MIN - minimization;
+*  GLP_MAX - maximization. */
+
+int glp_get_obj_dir(glp_prob *lp)
+{     int dir = lp->dir;
+      return dir;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_rows - retrieve number of rows
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_rows(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_rows returns the current number of rows in
+*  the specified problem object. */
+
+int glp_get_num_rows(glp_prob *lp)
+{     int m = lp->m;
+      return m;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_cols - retrieve number of columns
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_cols(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_cols returns the current number of columns
+*  in the specified problem object. */
+
+int glp_get_num_cols(glp_prob *lp)
+{     int n = lp->n;
+      return n;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_name - retrieve row name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_row_name(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_name returns a pointer to an internal
+*  buffer, which contains symbolic name of i-th row. However, if i-th
+*  row has no assigned name, the routine returns NULL. */
+
+const char *glp_get_row_name(glp_prob *lp, int i)
+{     char *name;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_name: i = %d; row number out of range\n",
+            i);
+      name = lp->row[i]->name;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_name - retrieve column name
+*
+*  SYNOPSIS
+*
+*  const char *glp_get_col_name(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_name returns a pointer to an internal
+*  buffer, which contains symbolic name of j-th column. However, if j-th
+*  column has no assigned name, the routine returns NULL. */
+
+const char *glp_get_col_name(glp_prob *lp, int j)
+{     char *name;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_name: j = %d; column number out of range\n"
+            , j);
+      name = lp->col[j]->name;
+      return name;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_type - retrieve row type
+*
+*  SYNOPSIS
+*
+*  int glp_get_row_type(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_type returns the type of i-th row, i.e. the
+*  type of corresponding auxiliary variable, as follows:
+*
+*  GLP_FR - free (unbounded) variable;
+*  GLP_LO - variable with lower bound;
+*  GLP_UP - variable with upper bound;
+*  GLP_DB - double-bounded variable;
+*  GLP_FX - fixed variable. */
+
+int glp_get_row_type(glp_prob *lp, int i)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_type: i = %d; row number out of range\n",
+            i);
+      return lp->row[i]->type;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_lb - retrieve row lower bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_lb(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_lb returns the lower bound of i-th row, i.e.
+*  the lower bound of corresponding auxiliary variable. However, if the
+*  row has no lower bound, the routine returns -DBL_MAX. */
+
+double glp_get_row_lb(glp_prob *lp, int i)
+{     double lb;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_lb: i = %d; row number out of range\n", i);
+      switch (lp->row[i]->type)
+      {  case GLP_FR:
+         case GLP_UP:
+            lb = -DBL_MAX; break;
+         case GLP_LO:
+         case GLP_DB:
+         case GLP_FX:
+            lb = lp->row[i]->lb; break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_ub - retrieve row upper bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_ub(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_ub returns the upper bound of i-th row, i.e.
+*  the upper bound of corresponding auxiliary variable. However, if the
+*  row has no upper bound, the routine returns +DBL_MAX. */
+
+double glp_get_row_ub(glp_prob *lp, int i)
+{     double ub;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_ub: i = %d; row number out of range\n", i);
+      switch (lp->row[i]->type)
+      {  case GLP_FR:
+         case GLP_LO:
+            ub = +DBL_MAX; break;
+         case GLP_UP:
+         case GLP_DB:
+         case GLP_FX:
+            ub = lp->row[i]->ub; break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_type - retrieve column type
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_type(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_type returns the type of j-th column, i.e.
+*  the type of corresponding structural variable, as follows:
+*
+*  GLP_FR - free (unbounded) variable;
+*  GLP_LO - variable with lower bound;
+*  GLP_UP - variable with upper bound;
+*  GLP_DB - double-bounded variable;
+*  GLP_FX - fixed variable. */
+
+int glp_get_col_type(glp_prob *lp, int j)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_type: j = %d; column number out of range\n"
+            , j);
+      return lp->col[j]->type;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_lb - retrieve column lower bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_lb(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_lb returns the lower bound of j-th column,
+*  i.e. the lower bound of corresponding structural variable. However,
+*  if the column has no lower bound, the routine returns -DBL_MAX. */
+
+double glp_get_col_lb(glp_prob *lp, int j)
+{     double lb;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_lb: j = %d; column number out of range\n",
+            j);
+      switch (lp->col[j]->type)
+      {  case GLP_FR:
+         case GLP_UP:
+            lb = -DBL_MAX; break;
+         case GLP_LO:
+         case GLP_DB:
+         case GLP_FX:
+            lb = lp->col[j]->lb; break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_ub - retrieve column upper bound
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_ub(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_ub returns the upper bound of j-th column,
+*  i.e. the upper bound of corresponding structural variable. However,
+*  if the column has no upper bound, the routine returns +DBL_MAX. */
+
+double glp_get_col_ub(glp_prob *lp, int j)
+{     double ub;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_ub: j = %d; column number out of range\n",
+            j);
+      switch (lp->col[j]->type)
+      {  case GLP_FR:
+         case GLP_LO:
+            ub = +DBL_MAX; break;
+         case GLP_UP:
+         case GLP_DB:
+         case GLP_FX:
+            ub = lp->col[j]->ub; break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_coef - retrieve obj. coefficient or constant term
+*
+*  SYNOPSIS
+*
+*  double glp_get_obj_coef(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_coef returns the objective coefficient at
+*  j-th structural variable (column) of the specified problem object.
+*
+*  If the parameter j is zero, the routine returns the constant term
+*  ("shift") of the objective function. */
+
+double glp_get_obj_coef(glp_prob *lp, int j)
+{     if (!(0 <= j && j <= lp->n))
+         xerror("glp_get_obj_coef: j = %d; column number out of range\n"
+            , j);
+      return j == 0 ? lp->c0 : lp->col[j]->coef;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_nz - retrieve number of constraint coefficients
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_nz(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_nz returns the number of (non-zero) elements
+*  in the constraint matrix of the specified problem object. */
+
+int glp_get_num_nz(glp_prob *lp)
+{     int nnz = lp->nnz;
+      return nnz;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_mat_row - retrieve row of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_mat_row scans (non-zero) elements of i-th row
+*  of the constraint matrix of the specified problem object and stores
+*  their column indices and numeric values to locations ind[1], ...,
+*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
+*  is the number of elements in i-th row, n is the number of columns.
+*
+*  The parameter ind and/or val can be specified as NULL, in which case
+*  corresponding information is not stored.
+*
+*  RETURNS
+*
+*  The routine glp_get_mat_row returns the length len, i.e. the number
+*  of (non-zero) elements in i-th row. */
+
+int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[])
+{     GLPAIJ *aij;
+      int len;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_mat_row: i = %d; row number out of range\n",
+            i);
+      len = 0;
+      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+      {  len++;
+         if (ind != NULL) ind[len] = aij->col->j;
+         if (val != NULL) val[len] = aij->val;
+      }
+      xassert(len <= lp->n);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_mat_col - retrieve column of the constraint matrix
+*
+*  SYNOPSIS
+*
+*  int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_mat_col scans (non-zero) elements of j-th column
+*  of the constraint matrix of the specified problem object and stores
+*  their row indices and numeric values to locations ind[1], ...,
+*  ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m
+*  is the number of elements in j-th column, m is the number of rows.
+*
+*  The parameter ind or/and val can be specified as NULL, in which case
+*  corresponding information is not stored.
+*
+*  RETURNS
+*
+*  The routine glp_get_mat_col returns the length len, i.e. the number
+*  of (non-zero) elements in j-th column. */
+
+int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[])
+{     GLPAIJ *aij;
+      int len;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_mat_col: j = %d; column number out of range\n",
+            j);
+      len = 0;
+      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+      {  len++;
+         if (ind != NULL) ind[len] = aij->row->i;
+         if (val != NULL) val[len] = aij->val;
+      }
+      xassert(len <= lp->m);
+      return len;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi03.c
===================================================================
--- deps/glpk/src/glpapi03.c	(revision 9)
+++ deps/glpk/src/glpapi03.c	(revision 9)
@@ -0,0 +1,166 @@
+/* glpapi03.c (row and column searching routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_create_index - create the name index
+*
+*  SYNOPSIS
+*
+*  void glp_create_index(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_create_index creates the name index for the
+*  specified problem object. The name index is an auxiliary data
+*  structure, which is intended to quickly (i.e. for logarithmic time)
+*  find rows and columns by their names.
+*
+*  This routine can be called at any time. If the name index already
+*  exists, the routine does nothing. */
+
+void glp_create_index(glp_prob *lp)
+{     GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      /* create row name index */
+      if (lp->r_tree == NULL)
+      {  lp->r_tree = avl_create_tree(avl_strcmp, NULL);
+         for (i = 1; i <= lp->m; i++)
+         {  row = lp->row[i];
+            xassert(row->node == NULL);
+            if (row->name != NULL)
+            {  row->node = avl_insert_node(lp->r_tree, row->name);
+               avl_set_node_link(row->node, row);
+            }
+         }
+      }
+      /* create column name index */
+      if (lp->c_tree == NULL)
+      {  lp->c_tree = avl_create_tree(avl_strcmp, NULL);
+         for (j = 1; j <= lp->n; j++)
+         {  col = lp->col[j];
+            xassert(col->node == NULL);
+            if (col->name != NULL)
+            {  col->node = avl_insert_node(lp->c_tree, col->name);
+               avl_set_node_link(col->node, col);
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_find_row - find row by its name
+*
+*  SYNOPSIS
+*
+*  int glp_find_row(glp_prob *lp, const char *name);
+*
+*  RETURNS
+*
+*  The routine glp_find_row returns the ordinal number of a row,
+*  which is assigned (by the routine glp_set_row_name) the specified
+*  symbolic name. If no such row exists, the routine returns 0. */
+
+int glp_find_row(glp_prob *lp, const char *name)
+{     AVLNODE *node;
+      int i = 0;
+      if (lp->r_tree == NULL)
+         xerror("glp_find_row: row name index does not exist\n");
+      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+      {  node = avl_find_node(lp->r_tree, name);
+         if (node != NULL)
+            i = ((GLPROW *)avl_get_node_link(node))->i;
+      }
+      return i;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_find_col - find column by its name
+*
+*  SYNOPSIS
+*
+*  int glp_find_col(glp_prob *lp, const char *name);
+*
+*  RETURNS
+*
+*  The routine glp_find_col returns the ordinal number of a column,
+*  which is assigned (by the routine glp_set_col_name) the specified
+*  symbolic name. If no such column exists, the routine returns 0. */
+
+int glp_find_col(glp_prob *lp, const char *name)
+{     AVLNODE *node;
+      int j = 0;
+      if (lp->c_tree == NULL)
+         xerror("glp_find_col: column name index does not exist\n");
+      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+      {  node = avl_find_node(lp->c_tree, name);
+         if (node != NULL)
+            j = ((GLPCOL *)avl_get_node_link(node))->j;
+      }
+      return j;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_delete_index - delete the name index
+*
+*  SYNOPSIS
+*
+*  void glp_delete_index(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_delete_index deletes the name index previously
+*  created by the routine glp_create_index and frees the memory
+*  allocated to this auxiliary data structure.
+*
+*  This routine can be called at any time. If the name index does not
+*  exist, the routine does nothing. */
+
+void glp_delete_index(glp_prob *lp)
+{     int i, j;
+      /* delete row name index */
+      if (lp->r_tree != NULL)
+      {  for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL;
+         avl_delete_tree(lp->r_tree), lp->r_tree = NULL;
+      }
+      /* delete column name index */
+      if (lp->c_tree != NULL)
+      {  for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL;
+         avl_delete_tree(lp->c_tree), lp->c_tree = NULL;
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi04.c
===================================================================
--- deps/glpk/src/glpapi04.c	(revision 9)
+++ deps/glpk/src/glpapi04.c	(revision 9)
@@ -0,0 +1,156 @@
+/* glpapi04.c (problem scaling routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_rii - set (change) row scale factor
+*
+*  SYNOPSIS
+*
+*  void glp_set_rii(glp_prob *lp, int i, double rii);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_rii sets (changes) the scale factor r[i,i] for
+*  i-th row of the specified problem object. */
+
+void glp_set_rii(glp_prob *lp, int i, double rii)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_rii: i = %d; row number out of range\n", i);
+      if (rii <= 0.0)
+         xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n",
+            i, rii);
+      if (lp->valid && lp->row[i]->rii != rii)
+      {  GLPAIJ *aij;
+         for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  if (aij->col->stat == GLP_BS)
+            {  /* invalidate the basis factorization */
+               lp->valid = 0;
+               break;
+            }
+         }
+      }
+      lp->row[i]->rii = rii;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set sjj - set (change) column scale factor
+*
+*  SYNOPSIS
+*
+*  void glp_set_sjj(glp_prob *lp, int j, double sjj);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_sjj sets (changes) the scale factor s[j,j] for
+*  j-th column of the specified problem object. */
+
+void glp_set_sjj(glp_prob *lp, int j, double sjj)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_sjj: j = %d; column number out of range\n", j);
+      if (sjj <= 0.0)
+         xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n",
+            j, sjj);
+      if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat ==
+         GLP_BS)
+      {  /* invalidate the basis factorization */
+         lp->valid = 0;
+      }
+      lp->col[j]->sjj = sjj;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_rii - retrieve row scale factor
+*
+*  SYNOPSIS
+*
+*  double glp_get_rii(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_rii returns current scale factor r[i,i] for i-th
+*  row of the specified problem object. */
+
+double glp_get_rii(glp_prob *lp, int i)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_rii: i = %d; row number out of range\n", i);
+      return lp->row[i]->rii;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_sjj - retrieve column scale factor
+*
+*  SYNOPSIS
+*
+*  double glp_get_sjj(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_sjj returns current scale factor s[j,j] for j-th
+*  column of the specified problem object. */
+
+double glp_get_sjj(glp_prob *lp, int j)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_sjj: j = %d; column number out of range\n", j);
+      return lp->col[j]->sjj;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_unscale_prob - unscale problem data
+*
+*  SYNOPSIS
+*
+*  void glp_unscale_prob(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_unscale_prob performs unscaling of problem data for
+*  the specified problem object.
+*
+*  "Unscaling" means replacing the current scaling matrices R and S by
+*  unity matrices that cancels the scaling effect. */
+
+void glp_unscale_prob(glp_prob *lp)
+{     int m = glp_get_num_rows(lp);
+      int n = glp_get_num_cols(lp);
+      int i, j;
+      for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0);
+      for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi05.c
===================================================================
--- deps/glpk/src/glpapi05.c	(revision 9)
+++ deps/glpk/src/glpapi05.c	(revision 9)
@@ -0,0 +1,168 @@
+/* glpapi05.c (LP basis constructing routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_row_stat - set (change) row status
+*
+*  SYNOPSIS
+*
+*  void glp_set_row_stat(glp_prob *lp, int i, int stat);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_row_stat sets (changes) status of the auxiliary
+*  variable associated with i-th row.
+*
+*  The new status of the auxiliary variable should be specified by the
+*  parameter stat as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable;
+*  GLP_NU - non-basic variable on its upper bound; if the variable is
+*           not double-bounded, this means the same as GLP_NL (only in
+*           case of this routine);
+*  GLP_NF - the same as GLP_NL (only in case of this routine);
+*  GLP_NS - the same as GLP_NL (only in case of this routine). */
+
+void glp_set_row_stat(glp_prob *lp, int i, int stat)
+{     GLPROW *row;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_set_row_stat: i = %d; row number out of range\n",
+            i);
+      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
+            stat == GLP_NF || stat == GLP_NS))
+         xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n",
+            i, stat);
+      row = lp->row[i];
+      if (stat != GLP_BS)
+      {  switch (row->type)
+         {  case GLP_FR: stat = GLP_NF; break;
+            case GLP_LO: stat = GLP_NL; break;
+            case GLP_UP: stat = GLP_NU; break;
+            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
+            case GLP_FX: stat = GLP_NS; break;
+            default: xassert(row != row);
+         }
+      }
+      if (row->stat == GLP_BS && stat != GLP_BS ||
+          row->stat != GLP_BS && stat == GLP_BS)
+      {  /* invalidate the basis factorization */
+         lp->valid = 0;
+      }
+      row->stat = stat;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_stat - set (change) column status
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_stat(glp_prob *lp, int j, int stat);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_stat sets (changes) status of the structural
+*  variable associated with j-th column.
+*
+*  The new status of the structural variable should be specified by the
+*  parameter stat as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable;
+*  GLP_NU - non-basic variable on its upper bound; if the variable is
+*           not double-bounded, this means the same as GLP_NL (only in
+*           case of this routine);
+*  GLP_NF - the same as GLP_NL (only in case of this routine);
+*  GLP_NS - the same as GLP_NL (only in case of this routine). */
+
+void glp_set_col_stat(glp_prob *lp, int j, int stat)
+{     GLPCOL *col;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_set_col_stat: j = %d; column number out of range\n"
+            , j);
+      if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU ||
+            stat == GLP_NF || stat == GLP_NS))
+         xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n",
+            j, stat);
+      col = lp->col[j];
+      if (stat != GLP_BS)
+      {  switch (col->type)
+         {  case GLP_FR: stat = GLP_NF; break;
+            case GLP_LO: stat = GLP_NL; break;
+            case GLP_UP: stat = GLP_NU; break;
+            case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break;
+            case GLP_FX: stat = GLP_NS; break;
+            default: xassert(col != col);
+         }
+      }
+      if (col->stat == GLP_BS && stat != GLP_BS ||
+          col->stat != GLP_BS && stat == GLP_BS)
+      {  /* invalidate the basis factorization */
+         lp->valid = 0;
+      }
+      col->stat = stat;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_std_basis - construct standard initial LP basis
+*
+*  SYNOPSIS
+*
+*  void glp_std_basis(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_std_basis builds the "standard" (trivial) initial
+*  basis for the specified problem object.
+*
+*  In the "standard" basis all auxiliary variables are basic, and all
+*  structural variables are non-basic. */
+
+void glp_std_basis(glp_prob *lp)
+{     int i, j;
+      /* make all auxiliary variables basic */
+      for (i = 1; i <= lp->m; i++)
+         glp_set_row_stat(lp, i, GLP_BS);
+      /* make all structural variables non-basic */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub))
+            glp_set_col_stat(lp, j, GLP_NU);
+         else
+            glp_set_col_stat(lp, j, GLP_NL);
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi06.c
===================================================================
--- deps/glpk/src/glpapi06.c	(revision 9)
+++ deps/glpk/src/glpapi06.c	(revision 9)
@@ -0,0 +1,806 @@
+/* glpapi06.c (simplex method routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+#include "glpnpp.h"
+#include "glpspx.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_simplex - solve LP problem with the simplex method
+*
+*  SYNOPSIS
+*
+*  int glp_simplex(glp_prob *P, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_simplex is a driver to the LP solver based on the
+*  simplex method. This routine retrieves problem data from the
+*  specified problem object, calls the solver to solve the problem
+*  instance, and stores results of computations back into the problem
+*  object.
+*
+*  The simplex solver has a set of control parameters. Values of the
+*  control parameters can be passed in a structure glp_smcp, which the
+*  parameter parm points to.
+*
+*  The parameter parm can be specified as NULL, in which case the LP
+*  solver uses default settings.
+*
+*  RETURNS
+*
+*  0  The LP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EBADB
+*     Unable to start the search, because the initial basis specified
+*     in the problem object is invalid--the number of basic (auxiliary
+*     and structural) variables is not the same as the number of rows in
+*     the problem object.
+*
+*  GLP_ESING
+*     Unable to start the search, because the basis matrix correspodning
+*     to the initial basis is singular within the working precision.
+*
+*  GLP_ECOND
+*     Unable to start the search, because the basis matrix correspodning
+*     to the initial basis is ill-conditioned, i.e. its condition number
+*     is too large.
+*
+*  GLP_EBOUND
+*     Unable to start the search, because some double-bounded variables
+*     have incorrect bounds.
+*
+*  GLP_EFAIL
+*     The search was prematurely terminated due to the solver failure.
+*
+*  GLP_EOBJLL
+*     The search was prematurely terminated, because the objective
+*     function being maximized has reached its lower limit and continues
+*     decreasing (dual simplex only).
+*
+*  GLP_EOBJUL
+*     The search was prematurely terminated, because the objective
+*     function being minimized has reached its upper limit and continues
+*     increasing (dual simplex only).
+*
+*  GLP_EITLIM
+*     The search was prematurely terminated, because the simplex
+*     iteration limit has been exceeded.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded.
+*
+*  GLP_ENOPFS
+*     The LP problem instance has no primal feasible solution (only if
+*     the LP presolver is used).
+*
+*  GLP_ENODFS
+*     The LP problem instance has no dual feasible solution (only if the
+*     LP presolver is used). */
+
+static void trivial_lp(glp_prob *P, const glp_smcp *parm)
+{     /* solve trivial LP which has empty constraint matrix */
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      double p_infeas, d_infeas, zeta;
+      P->valid = 0;
+      P->pbs_stat = P->dbs_stat = GLP_FEAS;
+      P->obj_val = P->c0;
+      P->some = 0;
+      p_infeas = d_infeas = 0.0;
+      /* make all auxiliary variables basic */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         row->stat = GLP_BS;
+         row->prim = row->dual = 0.0;
+         /* check primal feasibility */
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+         {  /* row has lower bound */
+            if (row->lb > + parm->tol_bnd)
+            {  P->pbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth != GLP_PRIMAL)
+                  P->some = i;
+            }
+            if (p_infeas < + row->lb)
+               p_infeas = + row->lb;
+         }
+         if (row->type == GLP_UP || row->type == GLP_DB ||
+             row->type == GLP_FX)
+         {  /* row has upper bound */
+            if (row->ub < - parm->tol_bnd)
+            {  P->pbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth != GLP_PRIMAL)
+                  P->some = i;
+            }
+            if (p_infeas < - row->ub)
+               p_infeas = - row->ub;
+         }
+      }
+      /* determine scale factor for the objective row */
+      zeta = 1.0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (zeta < fabs(col->coef)) zeta = fabs(col->coef);
+      }
+      zeta = (P->dir == GLP_MIN ? +1.0 : -1.0) / zeta;
+      /* make all structural variables non-basic */
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->type == GLP_FR)
+            col->stat = GLP_NF, col->prim = 0.0;
+         else if (col->type == GLP_LO)
+lo:         col->stat = GLP_NL, col->prim = col->lb;
+         else if (col->type == GLP_UP)
+up:         col->stat = GLP_NU, col->prim = col->ub;
+         else if (col->type == GLP_DB)
+         {  if (zeta * col->coef > 0.0)
+               goto lo;
+            else if (zeta * col->coef < 0.0)
+               goto up;
+            else if (fabs(col->lb) <= fabs(col->ub))
+               goto lo;
+            else
+               goto up;
+         }
+         else if (col->type == GLP_FX)
+            col->stat = GLP_NS, col->prim = col->lb;
+         col->dual = col->coef;
+         P->obj_val += col->coef * col->prim;
+         /* check dual feasibility */
+         if (col->type == GLP_FR || col->type == GLP_LO)
+         {  /* column has no upper bound */
+            if (zeta * col->dual < - parm->tol_dj)
+            {  P->dbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth == GLP_PRIMAL)
+                  P->some = P->m + j;
+            }
+            if (d_infeas < - zeta * col->dual)
+               d_infeas = - zeta * col->dual;
+         }
+         if (col->type == GLP_FR || col->type == GLP_UP)
+         {  /* column has no lower bound */
+            if (zeta * col->dual > + parm->tol_dj)
+            {  P->dbs_stat = GLP_NOFEAS;
+               if (P->some == 0 && parm->meth == GLP_PRIMAL)
+                  P->some = P->m + j;
+            }
+            if (d_infeas < + zeta * col->dual)
+               d_infeas = + zeta * col->dual;
+         }
+      }
+      /* simulate the simplex solver output */
+      if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
+      {  xprintf("~%6d: obj = %17.9e  infeas = %10.3e\n", P->it_cnt,
+            P->obj_val, parm->meth == GLP_PRIMAL ? p_infeas : d_infeas);
+      }
+      if (parm->msg_lev >= GLP_MSG_ALL && parm->out_dly == 0)
+      {  if (P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)
+            xprintf("OPTIMAL SOLUTION FOUND\n");
+         else if (P->pbs_stat == GLP_NOFEAS)
+            xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+         else if (parm->meth == GLP_PRIMAL)
+            xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+         else
+            xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+      }
+      return;
+}
+
+static int solve_lp(glp_prob *P, const glp_smcp *parm)
+{     /* solve LP directly without using the preprocessor */
+      int ret;
+      if (!glp_bf_exists(P))
+      {  ret = glp_factorize(P);
+         if (ret == 0)
+            ;
+         else if (ret == GLP_EBADB)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: initial basis is invalid\n");
+         }
+         else if (ret == GLP_ESING)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: initial basis is singular\n");
+         }
+         else if (ret == GLP_ECOND)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf(
+                  "glp_simplex: initial basis is ill-conditioned\n");
+         }
+         else
+            xassert(ret != ret);
+         if (ret != 0) goto done;
+      }
+      if (parm->meth == GLP_PRIMAL)
+         ret = spx_primal(P, parm);
+      else if (parm->meth == GLP_DUALP)
+      {  ret = spx_dual(P, parm);
+         if (ret == GLP_EFAIL && P->valid)
+            ret = spx_primal(P, parm);
+      }
+      else if (parm->meth == GLP_DUAL)
+         ret = spx_dual(P, parm);
+      else
+         xassert(parm != parm);
+done: return ret;
+}
+
+static int preprocess_and_solve_lp(glp_prob *P, const glp_smcp *parm)
+{     /* solve LP using the preprocessor */
+      NPP *npp;
+      glp_prob *lp = NULL;
+      glp_bfcp bfcp;
+      int ret;
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Preprocessing...\n");
+      /* create preprocessor workspace */
+      npp = npp_create_wksp();
+      /* load original problem into the preprocessor workspace */
+      npp_load_prob(npp, P, GLP_OFF, GLP_SOL, GLP_OFF);
+      /* process LP prior to applying primal/dual simplex method */
+      ret = npp_simplex(npp, parm);
+      if (ret == 0)
+         ;
+      else if (ret == GLP_ENOPFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
+      }
+      else if (ret == GLP_ENODFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+      }
+      else
+         xassert(ret != ret);
+      if (ret != 0) goto done;
+      /* build transformed LP */
+      lp = glp_create_prob();
+      npp_build_prob(npp, lp);
+      /* if the transformed LP is empty, it has empty solution, which
+         is optimal */
+      if (lp->m == 0 && lp->n == 0)
+      {  lp->pbs_stat = lp->dbs_stat = GLP_FEAS;
+         lp->obj_val = lp->c0;
+         if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0)
+         {  xprintf("~%6d: obj = %17.9e  infeas = %10.3e\n", P->it_cnt,
+               lp->obj_val, 0.0);
+         }
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("OPTIMAL SOLUTION FOUND BY LP PREPROCESSOR\n");
+         goto post;
+      }
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            lp->m, lp->m == 1 ? "" : "s", lp->n, lp->n == 1 ? "" : "s",
+            lp->nnz, lp->nnz == 1 ? "" : "s");
+      }
+      /* inherit basis factorization control parameters */
+      glp_get_bfcp(P, &bfcp);
+      glp_set_bfcp(lp, &bfcp);
+      /* scale the transformed problem */
+      {  ENV *env = get_env_ptr();
+         int term_out = env->term_out;
+         if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+            env->term_out = GLP_OFF;
+         else
+            env->term_out = GLP_ON;
+         glp_scale_prob(lp, GLP_SF_AUTO);
+         env->term_out = term_out;
+      }
+      /* build advanced initial basis */
+      {  ENV *env = get_env_ptr();
+         int term_out = env->term_out;
+         if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+            env->term_out = GLP_OFF;
+         else
+            env->term_out = GLP_ON;
+         glp_adv_basis(lp, 0);
+         env->term_out = term_out;
+      }
+      /* solve the transformed LP */
+      lp->it_cnt = P->it_cnt;
+      ret = solve_lp(lp, parm);
+      P->it_cnt = lp->it_cnt;
+      /* only optimal solution can be postprocessed */
+      if (!(ret == 0 && lp->pbs_stat == GLP_FEAS && lp->dbs_stat ==
+            GLP_FEAS))
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_simplex: unable to recover undefined or non-op"
+               "timal solution\n");
+         if (ret == 0)
+         {  if (lp->pbs_stat == GLP_NOFEAS)
+               ret = GLP_ENOPFS;
+            else if (lp->dbs_stat == GLP_NOFEAS)
+               ret = GLP_ENODFS;
+            else
+               xassert(lp != lp);
+         }
+         goto done;
+      }
+post: /* postprocess solution from the transformed LP */
+      npp_postprocess(npp, lp);
+      /* the transformed LP is no longer needed */
+      glp_delete_prob(lp), lp = NULL;
+      /* store solution to the original problem */
+      npp_unload_sol(npp, P);
+      /* the original LP has been successfully solved */
+      ret = 0;
+done: /* delete the transformed LP, if it exists */
+      if (lp != NULL) glp_delete_prob(lp);
+      /* delete preprocessor workspace */
+      npp_delete_wksp(npp);
+      return ret;
+}
+
+int glp_simplex(glp_prob *P, const glp_smcp *parm)
+{     /* solve LP problem with the simplex method */
+      glp_smcp _parm;
+      int i, j, ret;
+      /* check problem object */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_simplex: P = %p; invalid problem object\n", P);
+      if (P->tree != NULL && P->tree->reason != 0)
+         xerror("glp_simplex: operation not allowed\n");
+      /* check control parameters */
+      if (parm == NULL)
+         parm = &_parm, glp_init_smcp((glp_smcp *)parm);
+      if (!(parm->msg_lev == GLP_MSG_OFF ||
+            parm->msg_lev == GLP_MSG_ERR ||
+            parm->msg_lev == GLP_MSG_ON  ||
+            parm->msg_lev == GLP_MSG_ALL ||
+            parm->msg_lev == GLP_MSG_DBG))
+         xerror("glp_simplex: msg_lev = %d; invalid parameter\n",
+            parm->msg_lev);
+      if (!(parm->meth == GLP_PRIMAL ||
+            parm->meth == GLP_DUALP  ||
+            parm->meth == GLP_DUAL))
+         xerror("glp_simplex: meth = %d; invalid parameter\n",
+            parm->meth);
+      if (!(parm->pricing == GLP_PT_STD ||
+            parm->pricing == GLP_PT_PSE))
+         xerror("glp_simplex: pricing = %d; invalid parameter\n",
+            parm->pricing);
+      if (!(parm->r_test == GLP_RT_STD ||
+            parm->r_test == GLP_RT_HAR))
+         xerror("glp_simplex: r_test = %d; invalid parameter\n",
+            parm->r_test);
+      if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0))
+         xerror("glp_simplex: tol_bnd = %g; invalid parameter\n",
+            parm->tol_bnd);
+      if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0))
+         xerror("glp_simplex: tol_dj = %g; invalid parameter\n",
+            parm->tol_dj);
+      if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0))
+         xerror("glp_simplex: tol_piv = %g; invalid parameter\n",
+            parm->tol_piv);
+      if (parm->it_lim < 0)
+         xerror("glp_simplex: it_lim = %d; invalid parameter\n",
+            parm->it_lim);
+      if (parm->tm_lim < 0)
+         xerror("glp_simplex: tm_lim = %d; invalid parameter\n",
+            parm->tm_lim);
+      if (parm->out_frq < 1)
+         xerror("glp_simplex: out_frq = %d; invalid parameter\n",
+            parm->out_frq);
+      if (parm->out_dly < 0)
+         xerror("glp_simplex: out_dly = %d; invalid parameter\n",
+            parm->out_dly);
+      if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
+         xerror("glp_simplex: presolve = %d; invalid parameter\n",
+            parm->presolve);
+      /* basic solution is currently undefined */
+      P->pbs_stat = P->dbs_stat = GLP_UNDEF;
+      P->obj_val = 0.0;
+      P->some = 0;
+      /* check bounds of double-bounded variables */
+      for (i = 1; i <= P->m; i++)
+      {  GLPROW *row = P->row[i];
+         if (row->type == GLP_DB && row->lb >= row->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: row %d: lb = %g, ub = %g; incorrec"
+                  "t bounds\n", i, row->lb, row->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  GLPCOL *col = P->col[j];
+         if (col->type == GLP_DB && col->lb >= col->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_simplex: column %d: lb = %g, ub = %g; incor"
+                  "rect bounds\n", j, col->lb, col->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* solve LP problem */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  xprintf("GLPK Simplex Optimizer, v%s\n", glp_version());
+         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+            P->nnz, P->nnz == 1 ? "" : "s");
+      }
+      if (P->nnz == 0)
+         trivial_lp(P, parm), ret = 0;
+      else if (!parm->presolve)
+         ret = solve_lp(P, parm);
+      else
+         ret = preprocess_and_solve_lp(P, parm);
+done: /* return to the application program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_smcp - initialize simplex method control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_smcp(glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_smcp initializes control parameters, which are
+*  used by the simplex solver, with default values.
+*
+*  Default values of the control parameters are stored in a glp_smcp
+*  structure, which the parameter parm points to. */
+
+void glp_init_smcp(glp_smcp *parm)
+{     parm->msg_lev = GLP_MSG_ALL;
+      parm->meth = GLP_PRIMAL;
+      parm->pricing = GLP_PT_PSE;
+      parm->r_test = GLP_RT_HAR;
+      parm->tol_bnd = 1e-7;
+      parm->tol_dj = 1e-7;
+      parm->tol_piv = 1e-10;
+      parm->obj_ll = -DBL_MAX;
+      parm->obj_ul = +DBL_MAX;
+      parm->it_lim = INT_MAX;
+      parm->tm_lim = INT_MAX;
+      parm->out_frq = 500;
+      parm->out_dly = 0;
+      parm->presolve = GLP_OFF;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_status - retrieve generic status of basic solution
+*
+*  SYNOPSIS
+*
+*  int glp_get_status(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_status reports the generic status of the basic
+*  solution for the specified problem object as follows:
+*
+*  GLP_OPT    - solution is optimal;
+*  GLP_FEAS   - solution is feasible;
+*  GLP_INFEAS - solution is infeasible;
+*  GLP_NOFEAS - problem has no feasible solution;
+*  GLP_UNBND  - problem has unbounded solution;
+*  GLP_UNDEF  - solution is undefined. */
+
+int glp_get_status(glp_prob *lp)
+{     int status;
+      status = glp_get_prim_stat(lp);
+      switch (status)
+      {  case GLP_FEAS:
+            switch (glp_get_dual_stat(lp))
+            {  case GLP_FEAS:
+                  status = GLP_OPT;
+                  break;
+               case GLP_NOFEAS:
+                  status = GLP_UNBND;
+                  break;
+               case GLP_UNDEF:
+               case GLP_INFEAS:
+                  status = status;
+                  break;
+               default:
+                  xassert(lp != lp);
+            }
+            break;
+         case GLP_UNDEF:
+         case GLP_INFEAS:
+         case GLP_NOFEAS:
+            status = status;
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return status;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_prim_stat - retrieve status of primal basic solution
+*
+*  SYNOPSIS
+*
+*  int glp_get_prim_stat(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_prim_stat reports the status of the primal basic
+*  solution for the specified problem object as follows:
+*
+*  GLP_UNDEF  - primal solution is undefined;
+*  GLP_FEAS   - primal solution is feasible;
+*  GLP_INFEAS - primal solution is infeasible;
+*  GLP_NOFEAS - no primal feasible solution exists. */
+
+int glp_get_prim_stat(glp_prob *lp)
+{     int pbs_stat = lp->pbs_stat;
+      return pbs_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_dual_stat - retrieve status of dual basic solution
+*
+*  SYNOPSIS
+*
+*  int glp_get_dual_stat(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_dual_stat reports the status of the dual basic
+*  solution for the specified problem object as follows:
+*
+*  GLP_UNDEF  - dual solution is undefined;
+*  GLP_FEAS   - dual solution is feasible;
+*  GLP_INFEAS - dual solution is infeasible;
+*  GLP_NOFEAS - no dual feasible solution exists. */
+
+int glp_get_dual_stat(glp_prob *lp)
+{     int dbs_stat = lp->dbs_stat;
+      return dbs_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_obj_val - retrieve objective value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_obj_val(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_obj_val returns value of the objective function
+*  for basic solution. */
+
+double glp_get_obj_val(glp_prob *lp)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double z;
+      z = lp->obj_val;
+      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+      return z;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_stat - retrieve row status
+*
+*  SYNOPSIS
+*
+*  int glp_get_row_stat(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_stat returns current status assigned to the
+*  auxiliary variable associated with i-th row as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on its lower bound;
+*  GLP_NU - non-basic variable on its upper bound;
+*  GLP_NF - non-basic free (unbounded) variable;
+*  GLP_NS - non-basic fixed variable. */
+
+int glp_get_row_stat(glp_prob *lp, int i)
+{     if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_stat: i = %d; row number out of range\n",
+            i);
+      return lp->row[i]->stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_prim - retrieve row primal value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_prim(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_prim returns primal value of the auxiliary
+*  variable associated with i-th row. */
+
+double glp_get_row_prim(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double prim;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_prim: i = %d; row number out of range\n",
+            i);
+      prim = lp->row[i]->prim;
+      /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
+      return prim;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_dual - retrieve row dual value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_row_dual(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_dual returns dual value (i.e. reduced cost)
+*  of the auxiliary variable associated with i-th row. */
+
+double glp_get_row_dual(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dual;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_dual: i = %d; row number out of range\n",
+            i);
+      dual = lp->row[i]->dual;
+      /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
+      return dual;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_stat - retrieve column status
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_stat(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_stat returns current status assigned to the
+*  structural variable associated with j-th column as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on its lower bound;
+*  GLP_NU - non-basic variable on its upper bound;
+*  GLP_NF - non-basic free (unbounded) variable;
+*  GLP_NS - non-basic fixed variable. */
+
+int glp_get_col_stat(glp_prob *lp, int j)
+{     if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_stat: j = %d; column number out of range\n"
+            , j);
+      return lp->col[j]->stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_prim - retrieve column primal value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_prim(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_prim returns primal value of the structural
+*  variable associated with j-th column. */
+
+double glp_get_col_prim(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double prim;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_prim: j = %d; column number out of range\n"
+            , j);
+      prim = lp->col[j]->prim;
+      /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/
+      return prim;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_dual - retrieve column dual value (basic solution)
+*
+*  SYNOPSIS
+*
+*  double glp_get_col_dual(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_dual returns dual value (i.e. reduced cost)
+*  of the structural variable associated with j-th column. */
+
+double glp_get_col_dual(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dual;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_dual: j = %d; column number out of range\n"
+            , j);
+      dual = lp->col[j]->dual;
+      /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/
+      return dual;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_unbnd_ray - determine variable causing unboundedness
+*
+*  SYNOPSIS
+*
+*  int glp_get_unbnd_ray(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_get_unbnd_ray returns the number k of a variable,
+*  which causes primal or dual unboundedness. If 1 <= k <= m, it is
+*  k-th auxiliary variable, and if m+1 <= k <= m+n, it is (k-m)-th
+*  structural variable, where m is the number of rows, n is the number
+*  of columns in the problem object. If such variable is not defined,
+*  the routine returns 0.
+*
+*  COMMENTS
+*
+*  If it is not exactly known which version of the simplex solver
+*  detected unboundedness, i.e. whether the unboundedness is primal or
+*  dual, it is sufficient to check the status of the variable reported
+*  with the routine glp_get_row_stat or glp_get_col_stat. If the
+*  variable is non-basic, the unboundedness is primal, otherwise, if
+*  the variable is basic, the unboundedness is dual (the latter case
+*  means that the problem has no primal feasible dolution). */
+
+int glp_get_unbnd_ray(glp_prob *lp)
+{     int k;
+      k = lp->some;
+      xassert(k >= 0);
+      if (k > lp->m + lp->n) k = 0;
+      return k;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi07.c
===================================================================
--- deps/glpk/src/glpapi07.c	(revision 9)
+++ deps/glpk/src/glpapi07.c	(revision 9)
@@ -0,0 +1,451 @@
+/* glpapi07.c (exact simplex solver) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpssx.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_exact - solve LP problem in exact arithmetic
+*
+*  SYNOPSIS
+*
+*  int glp_exact(glp_prob *lp, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_exact is a tentative implementation of the primal
+*  two-phase simplex method based on exact (rational) arithmetic. It is
+*  similar to the routine glp_simplex, however, for all internal
+*  computations it uses arithmetic of rational numbers, which is exact
+*  in mathematical sense, i.e. free of round-off errors unlike floating
+*  point arithmetic.
+*
+*  Note that the routine glp_exact uses inly two control parameters
+*  passed in the structure glp_smcp, namely, it_lim and tm_lim.
+*
+*  RETURNS
+*
+*  0  The LP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EBADB
+*     Unable to start the search, because the initial basis specified
+*     in the problem object is invalid--the number of basic (auxiliary
+*     and structural) variables is not the same as the number of rows in
+*     the problem object.
+*
+*  GLP_ESING
+*     Unable to start the search, because the basis matrix correspodning
+*     to the initial basis is exactly singular.
+*
+*  GLP_EBOUND
+*     Unable to start the search, because some double-bounded variables
+*     have incorrect bounds.
+*
+*  GLP_EFAIL
+*     The problem has no rows/columns.
+*
+*  GLP_EITLIM
+*     The search was prematurely terminated, because the simplex
+*     iteration limit has been exceeded.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded. */
+
+static void set_d_eps(mpq_t x, double val)
+{     /* convert double val to rational x obtaining a more adequate
+         fraction than provided by mpq_set_d due to allowing a small
+         approximation error specified by a given relative tolerance;
+         for example, mpq_set_d would give the following
+         1/3 ~= 0.333333333333333314829616256247391... ->
+             -> 6004799503160661/18014398509481984
+         while this routine gives exactly 1/3 */
+      int s, n, j;
+      double f, p, q, eps = 1e-9;
+      mpq_t temp;
+      xassert(-DBL_MAX <= val && val <= +DBL_MAX);
+#if 1 /* 30/VII-2008 */
+      if (val == floor(val))
+      {  /* if val is integral, do not approximate */
+         mpq_set_d(x, val);
+         goto done;
+      }
+#endif
+      if (val > 0.0)
+         s = +1;
+      else if (val < 0.0)
+         s = -1;
+      else
+      {  mpq_set_si(x, 0, 1);
+         goto done;
+      }
+      f = frexp(fabs(val), &n);
+      /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
+      fp2rat(f, 0.1 * eps, &p, &q);
+      /* f ~= p / q, where p and q are integers */
+      mpq_init(temp);
+      mpq_set_d(x, p);
+      mpq_set_d(temp, q);
+      mpq_div(x, x, temp);
+      mpq_set_si(temp, 1, 1);
+      for (j = 1; j <= abs(n); j++)
+         mpq_add(temp, temp, temp);
+      if (n > 0)
+         mpq_mul(x, x, temp);
+      else if (n < 0)
+         mpq_div(x, x, temp);
+      mpq_clear(temp);
+      if (s < 0) mpq_neg(x, x);
+      /* check that the desired tolerance has been attained */
+      xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val)));
+done: return;
+}
+
+static void load_data(SSX *ssx, LPX *lp)
+{     /* load LP problem data into simplex solver workspace */
+      int m = ssx->m;
+      int n = ssx->n;
+      int nnz = ssx->A_ptr[n+1]-1;
+      int j, k, type, loc, len, *ind;
+      double lb, ub, coef, *val;
+      xassert(lpx_get_num_rows(lp) == m);
+      xassert(lpx_get_num_cols(lp) == n);
+      xassert(lpx_get_num_nz(lp) == nnz);
+      /* types and bounds of rows and columns */
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  type = lpx_get_row_type(lp, k);
+            lb = lpx_get_row_lb(lp, k);
+            ub = lpx_get_row_ub(lp, k);
+         }
+         else
+         {  type = lpx_get_col_type(lp, k-m);
+            lb = lpx_get_col_lb(lp, k-m);
+            ub = lpx_get_col_ub(lp, k-m);
+         }
+         switch (type)
+         {  case LPX_FR: type = SSX_FR; break;
+            case LPX_LO: type = SSX_LO; break;
+            case LPX_UP: type = SSX_UP; break;
+            case LPX_DB: type = SSX_DB; break;
+            case LPX_FX: type = SSX_FX; break;
+            default: xassert(type != type);
+         }
+         ssx->type[k] = type;
+         set_d_eps(ssx->lb[k], lb);
+         set_d_eps(ssx->ub[k], ub);
+      }
+      /* optimization direction */
+      switch (lpx_get_obj_dir(lp))
+      {  case LPX_MIN: ssx->dir = SSX_MIN; break;
+         case LPX_MAX: ssx->dir = SSX_MAX; break;
+         default: xassert(lp != lp);
+      }
+      /* objective coefficients */
+      for (k = 0; k <= m+n; k++)
+      {  if (k == 0)
+            coef = lpx_get_obj_coef(lp, 0);
+         else if (k <= m)
+            coef = 0.0;
+         else
+            coef = lpx_get_obj_coef(lp, k-m);
+         set_d_eps(ssx->coef[k], coef);
+      }
+      /* constraint coefficients */
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      loc = 0;
+      for (j = 1; j <= n; j++)
+      {  ssx->A_ptr[j] = loc+1;
+         len = lpx_get_mat_col(lp, j, ind, val);
+         for (k = 1; k <= len; k++)
+         {  loc++;
+            ssx->A_ind[loc] = ind[k];
+            set_d_eps(ssx->A_val[loc], val[k]);
+         }
+      }
+      xassert(loc == nnz);
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+static int load_basis(SSX *ssx, LPX *lp)
+{     /* load current LP basis into simplex solver workspace */
+      int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      int *stat = ssx->stat;
+      int *Q_row = ssx->Q_row;
+      int *Q_col = ssx->Q_col;
+      int i, j, k;
+      xassert(lpx_get_num_rows(lp) == m);
+      xassert(lpx_get_num_cols(lp) == n);
+      /* statuses of rows and columns */
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+            stat[k] = lpx_get_row_stat(lp, k);
+         else
+            stat[k] = lpx_get_col_stat(lp, k-m);
+         switch (stat[k])
+         {  case LPX_BS:
+               stat[k] = SSX_BS;
+               break;
+            case LPX_NL:
+               stat[k] = SSX_NL;
+               xassert(type[k] == SSX_LO || type[k] == SSX_DB);
+               break;
+            case LPX_NU:
+               stat[k] = SSX_NU;
+               xassert(type[k] == SSX_UP || type[k] == SSX_DB);
+               break;
+            case LPX_NF:
+               stat[k] = SSX_NF;
+               xassert(type[k] == SSX_FR);
+               break;
+            case LPX_NS:
+               stat[k] = SSX_NS;
+               xassert(type[k] == SSX_FX);
+               break;
+            default:
+               xassert(stat != stat);
+         }
+      }
+      /* build permutation matix Q */
+      i = j = 0;
+      for (k = 1; k <= m+n; k++)
+      {  if (stat[k] == SSX_BS)
+         {  i++;
+            if (i > m) return 1;
+            Q_row[k] = i, Q_col[i] = k;
+         }
+         else
+         {  j++;
+            if (j > n) return 1;
+            Q_row[k] = m+j, Q_col[m+j] = k;
+         }
+      }
+      xassert(i == m && j == n);
+      return 0;
+}
+
+int glp_exact(glp_prob *lp, const glp_smcp *parm)
+{     glp_smcp _parm;
+      SSX *ssx;
+      int m = lpx_get_num_rows(lp);
+      int n = lpx_get_num_cols(lp);
+      int nnz = lpx_get_num_nz(lp);
+      int i, j, k, type, pst, dst, ret, *stat;
+      double lb, ub, *prim, *dual, sum;
+      if (parm == NULL)
+         parm = &_parm, glp_init_smcp((glp_smcp *)parm);
+      /* check control parameters */
+      if (parm->it_lim < 0)
+         xerror("glp_exact: it_lim = %d; invalid parameter\n",
+            parm->it_lim);
+      if (parm->tm_lim < 0)
+         xerror("glp_exact: tm_lim = %d; invalid parameter\n",
+            parm->tm_lim);
+      /* the problem must have at least one row and one column */
+      if (!(m > 0 && n > 0))
+      {  xprintf("glp_exact: problem has no rows/columns\n");
+         return GLP_EFAIL;
+      }
+#if 1
+      /* basic solution is currently undefined */
+      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+      lp->obj_val = 0.0;
+      lp->some = 0;
+#endif
+      /* check that all double-bounded variables have correct bounds */
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  type = lpx_get_row_type(lp, k);
+            lb = lpx_get_row_lb(lp, k);
+            ub = lpx_get_row_ub(lp, k);
+         }
+         else
+         {  type = lpx_get_col_type(lp, k-m);
+            lb = lpx_get_col_lb(lp, k-m);
+            ub = lpx_get_col_ub(lp, k-m);
+         }
+         if (type == LPX_DB && lb >= ub)
+         {  xprintf("glp_exact: %s %d has invalid bounds\n",
+               k <= m ? "row" : "column", k <= m ? k : k-m);
+            return GLP_EBOUND;
+         }
+      }
+      /* create the simplex solver workspace */
+      xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n",
+         m, n, nnz);
+#ifdef HAVE_GMP
+      xprintf("GNU MP bignum library is being used\n");
+#else
+      xprintf("GLPK bignum module is being used\n");
+      xprintf("(Consider installing GNU MP to attain a much better perf"
+         "ormance.)\n");
+#endif
+      ssx = ssx_create(m, n, nnz);
+      /* load LP problem data into the workspace */
+      load_data(ssx, lp);
+      /* load current LP basis into the workspace */
+      if (load_basis(ssx, lp))
+      {  xprintf("glp_exact: initial LP basis is invalid\n");
+         ret = GLP_EBADB;
+         goto done;
+      }
+      /* inherit some control parameters from the LP object */
+#if 0
+      ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
+      ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT);
+      ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM);
+#else
+      ssx->it_lim = parm->it_lim;
+      ssx->it_cnt = lp->it_cnt;
+      ssx->tm_lim = (double)parm->tm_lim / 1000.0;
+#endif
+      ssx->out_frq = 5.0;
+      ssx->tm_beg = xtime();
+      ssx->tm_lag = xlset(0);
+      /* solve LP */
+      ret = ssx_driver(ssx);
+      /* copy back some statistics to the LP object */
+#if 0
+      lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim);
+      lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt);
+      lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim);
+#else
+      lp->it_cnt = ssx->it_cnt;
+#endif
+      /* analyze the return code */
+      switch (ret)
+      {  case 0:
+            /* optimal solution found */
+            ret = 0;
+            pst = LPX_P_FEAS, dst = LPX_D_FEAS;
+            break;
+         case 1:
+            /* problem has no feasible solution */
+            ret = 0;
+            pst = LPX_P_NOFEAS, dst = LPX_D_INFEAS;
+            break;
+         case 2:
+            /* problem has unbounded solution */
+            ret = 0;
+            pst = LPX_P_FEAS, dst = LPX_D_NOFEAS;
+#if 1
+            xassert(1 <= ssx->q && ssx->q <= n);
+            lp->some = ssx->Q_col[m + ssx->q];
+            xassert(1 <= lp->some && lp->some <= m+n);
+#endif
+            break;
+         case 3:
+            /* iteration limit exceeded (phase I) */
+            ret = GLP_EITLIM;
+            pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
+            break;
+         case 4:
+            /* iteration limit exceeded (phase II) */
+            ret = GLP_EITLIM;
+            pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
+            break;
+         case 5:
+            /* time limit exceeded (phase I) */
+            ret = GLP_ETMLIM;
+            pst = LPX_P_INFEAS, dst = LPX_D_INFEAS;
+            break;
+         case 6:
+            /* time limit exceeded (phase II) */
+            ret = GLP_ETMLIM;
+            pst = LPX_P_FEAS, dst = LPX_D_INFEAS;
+            break;
+         case 7:
+            /* initial basis matrix is singular */
+            ret = GLP_ESING;
+            goto done;
+         default:
+            xassert(ret != ret);
+      }
+      /* obtain final basic solution components */
+      stat = xcalloc(1+m+n, sizeof(int));
+      prim = xcalloc(1+m+n, sizeof(double));
+      dual = xcalloc(1+m+n, sizeof(double));
+      for (k = 1; k <= m+n; k++)
+      {  if (ssx->stat[k] == SSX_BS)
+         {  i = ssx->Q_row[k]; /* x[k] = xB[i] */
+            xassert(1 <= i && i <= m);
+            stat[k] = LPX_BS;
+            prim[k] = mpq_get_d(ssx->bbar[i]);
+            dual[k] = 0.0;
+         }
+         else
+         {  j = ssx->Q_row[k] - m; /* x[k] = xN[j] */
+            xassert(1 <= j && j <= n);
+            switch (ssx->stat[k])
+            {  case SSX_NF:
+                  stat[k] = LPX_NF;
+                  prim[k] = 0.0;
+                  break;
+               case SSX_NL:
+                  stat[k] = LPX_NL;
+                  prim[k] = mpq_get_d(ssx->lb[k]);
+                  break;
+               case SSX_NU:
+                  stat[k] = LPX_NU;
+                  prim[k] = mpq_get_d(ssx->ub[k]);
+                  break;
+               case SSX_NS:
+                  stat[k] = LPX_NS;
+                  prim[k] = mpq_get_d(ssx->lb[k]);
+                  break;
+               default:
+                  xassert(ssx != ssx);
+            }
+            dual[k] = mpq_get_d(ssx->cbar[j]);
+         }
+      }
+      /* and store them into the LP object */
+      pst = pst - LPX_P_UNDEF + GLP_UNDEF;
+      dst = dst - LPX_D_UNDEF + GLP_UNDEF;
+      for (k = 1; k <= m+n; k++)
+         stat[k] = stat[k] - LPX_BS + GLP_BS;
+      sum = lpx_get_obj_coef(lp, 0);
+      for (j = 1; j <= n; j++)
+         sum += lpx_get_obj_coef(lp, j) * prim[m+j];
+      lpx_put_solution(lp, 1, &pst, &dst, &sum,
+         &stat[0], &prim[0], &dual[0], &stat[m], &prim[m], &dual[m]);
+      xfree(stat);
+      xfree(prim);
+      xfree(dual);
+done: /* delete the simplex solver workspace */
+      ssx_delete(ssx);
+      /* return to the application program */
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi08.c
===================================================================
--- deps/glpk/src/glpapi08.c	(revision 9)
+++ deps/glpk/src/glpapi08.c	(revision 9)
@@ -0,0 +1,389 @@
+/* glpapi08.c (interior-point method routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpipm.h"
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_interior - solve LP problem with the interior-point method
+*
+*  SYNOPSIS
+*
+*  int glp_interior(glp_prob *P, const glp_iptcp *parm);
+*
+*  The routine glp_interior is a driver to the LP solver based on the
+*  interior-point method.
+*
+*  The interior-point solver has a set of control parameters. Values of
+*  the control parameters can be passed in a structure glp_iptcp, which
+*  the parameter parm points to.
+*
+*  Currently this routine implements an easy variant of the primal-dual
+*  interior-point method based on Mehrotra's technique.
+*
+*  This routine transforms the original LP problem to an equivalent LP
+*  problem in the standard formulation (all constraints are equalities,
+*  all variables are non-negative), calls the routine ipm_main to solve
+*  the transformed problem, and then transforms an obtained solution to
+*  the solution of the original problem.
+*
+*  RETURNS
+*
+*  0  The LP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EFAIL
+*     The problem has no rows/columns.
+*
+*  GLP_ENOCVG
+*     Very slow convergence or divergence.
+*
+*  GLP_EITLIM
+*     Iteration limit exceeded.
+*
+*  GLP_EINSTAB
+*     Numerical instability on solving Newtonian system. */
+
+static void transform(NPP *npp)
+{     /* transform LP to the standard formulation */
+      NPPROW *row, *prev_row;
+      NPPCOL *col, *prev_col;
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+            npp_free_row(npp, row);
+         else if (row->lb == -DBL_MAX)
+            npp_leq_row(npp, row);
+         else if (row->ub == +DBL_MAX)
+            npp_geq_row(npp, row);
+         else if (row->lb != row->ub)
+         {  if (fabs(row->lb) < fabs(row->ub))
+               npp_geq_row(npp, row);
+            else
+               npp_leq_row(npp, row);
+         }
+      }
+      for (col = npp->c_tail; col != NULL; col = prev_col)
+      {  prev_col = col->prev;
+         if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
+            npp_free_col(npp, col);
+         else if (col->lb == -DBL_MAX)
+            npp_ubnd_col(npp, col);
+         else if (col->ub == +DBL_MAX)
+         {  if (col->lb != 0.0)
+               npp_lbnd_col(npp, col);
+         }
+         else if (col->lb != col->ub)
+         {  if (fabs(col->lb) < fabs(col->ub))
+            {  if (col->lb != 0.0)
+                  npp_lbnd_col(npp, col);
+            }
+            else
+               npp_ubnd_col(npp, col);
+            npp_dbnd_col(npp, col);
+         }
+         else
+            npp_fixed_col(npp, col);
+      }
+      for (row = npp->r_head; row != NULL; row = row->next)
+         xassert(row->lb == row->ub);
+      for (col = npp->c_head; col != NULL; col = col->next)
+         xassert(col->lb == 0.0 && col->ub == +DBL_MAX);
+      return;
+}
+
+int glp_interior(glp_prob *P, const glp_iptcp *parm)
+{     glp_iptcp _parm;
+      GLPROW *row;
+      GLPCOL *col;
+      NPP *npp = NULL;
+      glp_prob *prob = NULL;
+      int i, j, ret;
+      /* check control parameters */
+      if (parm == NULL)
+         glp_init_iptcp(&_parm), parm = &_parm;
+      if (!(parm->msg_lev == GLP_MSG_OFF ||
+            parm->msg_lev == GLP_MSG_ERR ||
+            parm->msg_lev == GLP_MSG_ON  ||
+            parm->msg_lev == GLP_MSG_ALL))
+         xerror("glp_interior: msg_lev = %d; invalid parameter\n",
+            parm->msg_lev);
+      if (!(parm->ord_alg == GLP_ORD_NONE ||
+            parm->ord_alg == GLP_ORD_QMD ||
+            parm->ord_alg == GLP_ORD_AMD ||
+            parm->ord_alg == GLP_ORD_SYMAMD))
+         xerror("glp_interior: ord_alg = %d; invalid parameter\n",
+            parm->ord_alg);
+      /* interior-point solution is currently undefined */
+      P->ipt_stat = GLP_UNDEF;
+      P->ipt_obj = 0.0;
+      /* check bounds of double-bounded variables */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type == GLP_DB && row->lb >= row->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_interior: row %d: lb = %g, ub = %g; incorre"
+                  "ct bounds\n", i, row->lb, row->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->type == GLP_DB && col->lb >= col->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_interior: column %d: lb = %g, ub = %g; inco"
+                  "rrect bounds\n", j, col->lb, col->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* transform LP to the standard formulation */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Original LP has %d row(s), %d column(s), and %d non-z"
+            "ero(s)\n", P->m, P->n, P->nnz);
+      npp = npp_create_wksp();
+      npp_load_prob(npp, P, GLP_OFF, GLP_IPT, GLP_ON);
+      transform(npp);
+      prob = glp_create_prob();
+      npp_build_prob(npp, prob);
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Working LP has %d row(s), %d column(s), and %d non-ze"
+            "ro(s)\n", prob->m, prob->n, prob->nnz);
+#if 1
+      /* currently empty problem cannot be solved */
+      if (!(prob->m > 0 && prob->n > 0))
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_interior: unable to solve empty problem\n");
+         ret = GLP_EFAIL;
+         goto done;
+      }
+#endif
+      /* scale the resultant LP */
+      {  ENV *env = get_env_ptr();
+         int term_out = env->term_out;
+         env->term_out = GLP_OFF;
+         glp_scale_prob(prob, GLP_SF_EQ);
+         env->term_out = term_out;
+      }
+      /* warn about dense columns */
+      if (parm->msg_lev >= GLP_MSG_ON && prob->m >= 200)
+      {  int len, cnt = 0;
+         for (j = 1; j <= prob->n; j++)
+         {  len = glp_get_mat_col(prob, j, NULL, NULL);
+            if ((double)len >= 0.20 * (double)prob->m) cnt++;
+         }
+         if (cnt == 1)
+            xprintf("WARNING: PROBLEM HAS ONE DENSE COLUMN\n");
+         else if (cnt > 0)
+            xprintf("WARNING: PROBLEM HAS %d DENSE COLUMNS\n", cnt);
+      }
+      /* solve the transformed LP */
+      ret = ipm_solve(prob, parm);
+      /* postprocess solution from the transformed LP */
+      npp_postprocess(npp, prob);
+      /* and store solution to the original LP */
+      npp_unload_sol(npp, P);
+done: /* free working program objects */
+      if (npp != NULL) npp_delete_wksp(npp);
+      if (prob != NULL) glp_delete_prob(prob);
+      /* return to the application program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_iptcp - initialize interior-point solver control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_iptcp(glp_iptcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_iptcp initializes control parameters, which are
+*  used by the interior-point solver, with default values.
+*
+*  Default values of the control parameters are stored in the glp_iptcp
+*  structure, which the parameter parm points to. */
+
+void glp_init_iptcp(glp_iptcp *parm)
+{     parm->msg_lev = GLP_MSG_ALL;
+      parm->ord_alg = GLP_ORD_AMD;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_status - retrieve status of interior-point solution
+*
+*  SYNOPSIS
+*
+*  int glp_ipt_status(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_status reports the status of solution found by
+*  the interior-point solver as follows:
+*
+*  GLP_UNDEF  - interior-point solution is undefined;
+*  GLP_OPT    - interior-point solution is optimal;
+*  GLP_INFEAS - interior-point solution is infeasible;
+*  GLP_NOFEAS - no feasible solution exists. */
+
+int glp_ipt_status(glp_prob *lp)
+{     int ipt_stat = lp->ipt_stat;
+      return ipt_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_obj_val - retrieve objective value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_obj_val(glp_prob *lp);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_obj_val returns value of the objective function
+*  for interior-point solution. */
+
+double glp_ipt_obj_val(glp_prob *lp)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double z;
+      z = lp->ipt_obj;
+      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+      return z;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_row_prim - retrieve row primal value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_row_prim(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_row_prim returns primal value of the auxiliary
+*  variable associated with i-th row. */
+
+double glp_ipt_row_prim(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double pval;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_ipt_row_prim: i = %d; row number out of range\n",
+            i);
+      pval = lp->row[i]->pval;
+      /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
+      return pval;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_row_dual - retrieve row dual value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_row_dual(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_row_dual returns dual value (i.e. reduced cost)
+*  of the auxiliary variable associated with i-th row. */
+
+double glp_ipt_row_dual(glp_prob *lp, int i)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dval;
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_ipt_row_dual: i = %d; row number out of range\n",
+            i);
+      dval = lp->row[i]->dval;
+      /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
+      return dval;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_col_prim - retrieve column primal value (interior point)
+*
+*  SYNOPSIS
+*
+*  double glp_ipt_col_prim(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_col_prim returns primal value of the structural
+*  variable associated with j-th column. */
+
+double glp_ipt_col_prim(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double pval;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_ipt_col_prim: j = %d; column number out of range\n"
+            , j);
+      pval = lp->col[j]->pval;
+      /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/
+      return pval;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ipt_col_dual - retrieve column dual value (interior point)
+*
+*  SYNOPSIS
+*
+*  #include "glplpx.h"
+*  double glp_ipt_col_dual(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_ipt_col_dual returns dual value (i.e. reduced cost)
+*  of the structural variable associated with j-th column. */
+
+double glp_ipt_col_dual(glp_prob *lp, int j)
+{     /*struct LPXCPS *cps = lp->cps;*/
+      double dval;
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_ipt_col_dual: j = %d; column number out of range\n"
+            , j);
+      dval = lp->col[j]->dval;
+      /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/
+      return dval;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi09.c
===================================================================
--- deps/glpk/src/glpapi09.c	(revision 9)
+++ deps/glpk/src/glpapi09.c	(revision 9)
@@ -0,0 +1,741 @@
+/* glpapi09.c (mixed integer programming routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_col_kind - set (change) column kind
+*
+*  SYNOPSIS
+*
+*  void glp_set_col_kind(glp_prob *mip, int j, int kind);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_col_kind sets (changes) the kind of j-th column
+*  (structural variable) as specified by the parameter kind:
+*
+*  GLP_CV - continuous variable;
+*  GLP_IV - integer variable;
+*  GLP_BV - binary variable. */
+
+void glp_set_col_kind(glp_prob *mip, int j, int kind)
+{     GLPCOL *col;
+      if (!(1 <= j && j <= mip->n))
+         xerror("glp_set_col_kind: j = %d; column number out of range\n"
+            , j);
+      col = mip->col[j];
+      switch (kind)
+      {  case GLP_CV:
+            col->kind = GLP_CV;
+            break;
+         case GLP_IV:
+            col->kind = GLP_IV;
+            break;
+         case GLP_BV:
+            col->kind = GLP_IV;
+            if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub ==
+               1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0);
+            break;
+         default:
+            xerror("glp_set_col_kind: j = %d; kind = %d; invalid column"
+               " kind\n", j, kind);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_kind - retrieve column kind
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_kind(glp_prob *mip, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_kind returns the kind of j-th column, i.e.
+*  the kind of corresponding structural variable, as follows:
+*
+*  GLP_CV - continuous variable;
+*  GLP_IV - integer variable;
+*  GLP_BV - binary variable */
+
+int glp_get_col_kind(glp_prob *mip, int j)
+{     GLPCOL *col;
+      int kind;
+      if (!(1 <= j && j <= mip->n))
+         xerror("glp_get_col_kind: j = %d; column number out of range\n"
+            , j);
+      col = mip->col[j];
+      kind = col->kind;
+      switch (kind)
+      {  case GLP_CV:
+            break;
+         case GLP_IV:
+            if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
+               kind = GLP_BV;
+            break;
+         default:
+            xassert(kind != kind);
+      }
+      return kind;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_int - retrieve number of integer columns
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_int(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_int returns the current number of columns,
+*  which are marked as integer. */
+
+int glp_get_num_int(glp_prob *mip)
+{     GLPCOL *col;
+      int j, count = 0;
+      for (j = 1; j <= mip->n; j++)
+      {  col = mip->col[j];
+         if (col->kind == GLP_IV) count++;
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_num_bin - retrieve number of binary columns
+*
+*  SYNOPSIS
+*
+*  int glp_get_num_bin(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine glp_get_num_bin returns the current number of columns,
+*  which are marked as binary. */
+
+int glp_get_num_bin(glp_prob *mip)
+{     GLPCOL *col;
+      int j, count = 0;
+      for (j = 1; j <= mip->n; j++)
+      {  col = mip->col[j];
+         if (col->kind == GLP_IV && col->type == GLP_DB && col->lb ==
+            0.0 && col->ub == 1.0) count++;
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_intopt - solve MIP problem with the branch-and-bound method
+*
+*  SYNOPSIS
+*
+*  int glp_intopt(glp_prob *P, const glp_iocp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_intopt is a driver to the MIP solver based on the
+*  branch-and-bound method.
+*
+*  On entry the problem object should contain optimal solution to LP
+*  relaxation (which can be obtained with the routine glp_simplex).
+*
+*  The MIP solver has a set of control parameters. Values of the control
+*  parameters can be passed in a structure glp_iocp, which the parameter
+*  parm points to.
+*
+*  The parameter parm can be specified as NULL, in which case the MIP
+*  solver uses default settings.
+*
+*  RETURNS
+*
+*  0  The MIP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EBOUND
+*     Unable to start the search, because some double-bounded variables
+*     have incorrect bounds or some integer variables have non-integer
+*     (fractional) bounds.
+*
+*  GLP_EROOT
+*     Unable to start the search, because optimal basis for initial LP
+*     relaxation is not provided.
+*
+*  GLP_EFAIL
+*     The search was prematurely terminated due to the solver failure.
+*
+*  GLP_EMIPGAP
+*     The search was prematurely terminated, because the relative mip
+*     gap tolerance has been reached.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded.
+*
+*  GLP_ENOPFS
+*     The MIP problem instance has no primal feasible solution (only if
+*     the MIP presolver is used).
+*
+*  GLP_ENODFS
+*     LP relaxation of the MIP problem instance has no dual feasible
+*     solution (only if the MIP presolver is used).
+*
+*  GLP_ESTOP
+*     The search was prematurely terminated by application. */
+
+static int solve_mip(glp_prob *P, const glp_iocp *parm)
+{     /* solve MIP directly without using the preprocessor */
+      glp_tree *T;
+      int ret;
+      /* optimal basis to LP relaxation must be provided */
+      if (glp_get_status(P) != GLP_OPT)
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_intopt: optimal basis to initial LP relaxation"
+               " not provided\n");
+         ret = GLP_EROOT;
+         goto done;
+      }
+      /* it seems all is ok */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Integer optimization begins...\n");
+      /* create the branch-and-bound tree */
+      T = ios_create_tree(P, parm);
+      /* solve the problem instance */
+      ret = ios_driver(T);
+      /* delete the branch-and-bound tree */
+      ios_delete_tree(T);
+      /* analyze exit code reported by the mip driver */
+      if (ret == 0)
+      {  if (P->mip_stat == GLP_FEAS)
+         {  if (parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("INTEGER OPTIMAL SOLUTION FOUND\n");
+            P->mip_stat = GLP_OPT;
+         }
+         else
+         {  if (parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
+            P->mip_stat = GLP_NOFEAS;
+         }
+      }
+      else if (ret == GLP_EMIPGAP)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA"
+               "TED\n");
+      }
+      else if (ret == GLP_ETMLIM)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+      }
+      else if (ret == GLP_EFAIL)
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_intopt: cannot solve current LP relaxation\n");
+      }
+      else if (ret == GLP_ESTOP)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("SEARCH TERMINATED BY APPLICATION\n");
+      }
+      else
+         xassert(ret != ret);
+done: return ret;
+}
+
+static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm)
+{     /* solve MIP using the preprocessor */
+      ENV *env = get_env_ptr();
+      int term_out = env->term_out;
+      NPP *npp;
+      glp_prob *mip = NULL;
+      glp_bfcp bfcp;
+      glp_smcp smcp;
+      int ret;
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Preprocessing...\n");
+      /* create preprocessor workspace */
+      npp = npp_create_wksp();
+      /* load original problem into the preprocessor workspace */
+      npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
+      /* process MIP prior to applying the branch-and-bound method */
+      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+         env->term_out = GLP_OFF;
+      else
+         env->term_out = GLP_ON;
+      ret = npp_integer(npp, parm);
+      env->term_out = term_out;
+      if (ret == 0)
+         ;
+      else if (ret == GLP_ENOPFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
+      }
+      else if (ret == GLP_ENODFS)
+      {  if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n");
+      }
+      else
+         xassert(ret != ret);
+      if (ret != 0) goto done;
+      /* build transformed MIP */
+      mip = glp_create_prob();
+      npp_build_prob(npp, mip);
+      /* if the transformed MIP is empty, it has empty solution, which
+         is optimal */
+      if (mip->m == 0 && mip->n == 0)
+      {  mip->mip_stat = GLP_OPT;
+         mip->mip_obj = mip->c0;
+         if (parm->msg_lev >= GLP_MSG_ALL)
+         {  xprintf("Objective value = %17.9e\n", mip->mip_obj);
+            xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR"
+               "\n");
+         }
+         goto post;
+      }
+      /* display some statistics */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  int ni = glp_get_num_int(mip);
+         int nb = glp_get_num_bin(mip);
+         char s[50];
+         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" :
+            "s", mip->nnz, mip->nnz == 1 ? "" : "s");
+         if (nb == 0)
+            strcpy(s, "none of");
+         else if (ni == 1 && nb == 1)
+            strcpy(s, "");
+         else if (nb == 1)
+            strcpy(s, "one of");
+         else if (nb == ni)
+            strcpy(s, "all of");
+         else
+            sprintf(s, "%d of", nb);
+         xprintf("%d integer variable%s, %s which %s binary\n",
+            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
+      }
+      /* inherit basis factorization control parameters */
+      glp_get_bfcp(P, &bfcp);
+      glp_set_bfcp(mip, &bfcp);
+      /* scale the transformed problem */
+      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+         env->term_out = GLP_OFF;
+      else
+         env->term_out = GLP_ON;
+      glp_scale_prob(mip,
+         GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP);
+      env->term_out = term_out;
+      /* build advanced initial basis */
+      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
+         env->term_out = GLP_OFF;
+      else
+         env->term_out = GLP_ON;
+      glp_adv_basis(mip, 0);
+      env->term_out = term_out;
+      /* solve initial LP relaxation */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Solving LP relaxation...\n");
+      glp_init_smcp(&smcp);
+      smcp.msg_lev = parm->msg_lev;
+      mip->it_cnt = P->it_cnt;
+      ret = glp_simplex(mip, &smcp);
+      P->it_cnt = mip->it_cnt;
+      if (ret != 0)
+      {  if (parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("glp_intopt: cannot solve LP relaxation\n");
+         ret = GLP_EFAIL;
+         goto done;
+      }
+      /* check status of the basic solution */
+      ret = glp_get_status(mip);
+      if (ret == GLP_OPT)
+         ret = 0;
+      else if (ret == GLP_NOFEAS)
+         ret = GLP_ENOPFS;
+      else if (ret == GLP_UNBND)
+         ret = GLP_ENODFS;
+      else
+         xassert(ret != ret);
+      if (ret != 0) goto done;
+      /* solve the transformed MIP */
+      mip->it_cnt = P->it_cnt;
+      ret = solve_mip(mip, parm);
+      P->it_cnt = mip->it_cnt;
+      /* only integer feasible solution can be postprocessed */
+      if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
+      {  P->mip_stat = mip->mip_stat;
+         goto done;
+      }
+      /* postprocess solution from the transformed MIP */
+post: npp_postprocess(npp, mip);
+      /* the transformed MIP is no longer needed */
+      glp_delete_prob(mip), mip = NULL;
+      /* store solution to the original problem */
+      npp_unload_sol(npp, P);
+done: /* delete the transformed MIP, if it exists */
+      if (mip != NULL) glp_delete_prob(mip);
+      /* delete preprocessor workspace */
+      npp_delete_wksp(npp);
+      return ret;
+}
+
+#ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */
+int _glp_intopt1(glp_prob *P, const glp_iocp *parm)
+{     xassert(P == P);
+      xassert(parm == parm);
+      xprintf("glp_intopt: no alien solver is available\n");
+      return GLP_EFAIL;
+}
+#endif
+
+int glp_intopt(glp_prob *P, const glp_iocp *parm)
+{     /* solve MIP problem with the branch-and-bound method */
+      glp_iocp _parm;
+      int i, j, ret;
+      /* check problem object */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_intopt: P = %p; invalid problem object\n", P);
+      if (P->tree != NULL)
+         xerror("glp_intopt: operation not allowed\n");
+      /* check control parameters */
+      if (parm == NULL)
+         parm = &_parm, glp_init_iocp((glp_iocp *)parm);
+      if (!(parm->msg_lev == GLP_MSG_OFF ||
+            parm->msg_lev == GLP_MSG_ERR ||
+            parm->msg_lev == GLP_MSG_ON  ||
+            parm->msg_lev == GLP_MSG_ALL ||
+            parm->msg_lev == GLP_MSG_DBG))
+         xerror("glp_intopt: msg_lev = %d; invalid parameter\n",
+            parm->msg_lev);
+      if (!(parm->br_tech == GLP_BR_FFV ||
+            parm->br_tech == GLP_BR_LFV ||
+            parm->br_tech == GLP_BR_MFV ||
+            parm->br_tech == GLP_BR_DTH ||
+            parm->br_tech == GLP_BR_PCH))
+         xerror("glp_intopt: br_tech = %d; invalid parameter\n",
+            parm->br_tech);
+      if (!(parm->bt_tech == GLP_BT_DFS ||
+            parm->bt_tech == GLP_BT_BFS ||
+            parm->bt_tech == GLP_BT_BLB ||
+            parm->bt_tech == GLP_BT_BPH))
+         xerror("glp_intopt: bt_tech = %d; invalid parameter\n",
+            parm->bt_tech);
+      if (!(0.0 < parm->tol_int && parm->tol_int < 1.0))
+         xerror("glp_intopt: tol_int = %g; invalid parameter\n",
+            parm->tol_int);
+      if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0))
+         xerror("glp_intopt: tol_obj = %g; invalid parameter\n",
+            parm->tol_obj);
+      if (parm->tm_lim < 0)
+         xerror("glp_intopt: tm_lim = %d; invalid parameter\n",
+            parm->tm_lim);
+      if (parm->out_frq < 0)
+         xerror("glp_intopt: out_frq = %d; invalid parameter\n",
+            parm->out_frq);
+      if (parm->out_dly < 0)
+         xerror("glp_intopt: out_dly = %d; invalid parameter\n",
+            parm->out_dly);
+      if (!(0 <= parm->cb_size && parm->cb_size <= 256))
+         xerror("glp_intopt: cb_size = %d; invalid parameter\n",
+            parm->cb_size);
+      if (!(parm->pp_tech == GLP_PP_NONE ||
+            parm->pp_tech == GLP_PP_ROOT ||
+            parm->pp_tech == GLP_PP_ALL))
+         xerror("glp_intopt: pp_tech = %d; invalid parameter\n",
+            parm->pp_tech);
+      if (parm->mip_gap < 0.0)
+         xerror("glp_intopt: mip_gap = %g; invalid parameter\n",
+            parm->mip_gap);
+      if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF))
+         xerror("glp_intopt: mir_cuts = %d; invalid parameter\n",
+            parm->mir_cuts);
+      if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF))
+         xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n",
+            parm->gmi_cuts);
+      if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF))
+         xerror("glp_intopt: cov_cuts = %d; invalid parameter\n",
+            parm->cov_cuts);
+      if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF))
+         xerror("glp_intopt: clq_cuts = %d; invalid parameter\n",
+            parm->clq_cuts);
+      if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
+         xerror("glp_intopt: presolve = %d; invalid parameter\n",
+            parm->presolve);
+      if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF))
+         xerror("glp_intopt: binarize = %d; invalid parameter\n",
+            parm->binarize);
+      if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF))
+         xerror("glp_intopt: fp_heur = %d; invalid parameter\n",
+            parm->fp_heur);
+#if 1 /* 28/V-2010 */
+      if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF))
+         xerror("glp_intopt: alien = %d; invalid parameter\n",
+            parm->alien);
+#endif
+      /* integer solution is currently undefined */
+      P->mip_stat = GLP_UNDEF;
+      P->mip_obj = 0.0;
+      /* check bounds of double-bounded variables */
+      for (i = 1; i <= P->m; i++)
+      {  GLPROW *row = P->row[i];
+         if (row->type == GLP_DB && row->lb >= row->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect"
+                  " bounds\n", i, row->lb, row->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  GLPCOL *col = P->col[j];
+         if (col->type == GLP_DB && col->lb >= col->ub)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr"
+                  "ect bounds\n", j, col->lb, col->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* bounds of all integer variables must be integral */
+      for (j = 1; j <= P->n; j++)
+      {  GLPCOL *col = P->col[j];
+         if (col->kind != GLP_IV) continue;
+         if (col->type == GLP_LO || col->type == GLP_DB)
+         {  if (col->lb != floor(col->lb))
+            {  if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("glp_intopt: integer column %d has non-intege"
+                     "r lower bound %g\n", j, col->lb);
+               ret = GLP_EBOUND;
+               goto done;
+            }
+         }
+         if (col->type == GLP_UP || col->type == GLP_DB)
+         {  if (col->ub != floor(col->ub))
+            {  if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("glp_intopt: integer column %d has non-intege"
+                     "r upper bound %g\n", j, col->ub);
+               ret = GLP_EBOUND;
+               goto done;
+            }
+         }
+         if (col->type == GLP_FX)
+         {  if (col->lb != floor(col->lb))
+            {  if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("glp_intopt: integer column %d has non-intege"
+                     "r fixed value %g\n", j, col->lb);
+               ret = GLP_EBOUND;
+               goto done;
+            }
+         }
+      }
+      /* solve MIP problem */
+      if (parm->msg_lev >= GLP_MSG_ALL)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         char s[50];
+         xprintf("GLPK Integer Optimizer, v%s\n", glp_version());
+         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+            P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+            P->nnz, P->nnz == 1 ? "" : "s");
+         if (nb == 0)
+            strcpy(s, "none of");
+         else if (ni == 1 && nb == 1)
+            strcpy(s, "");
+         else if (nb == 1)
+            strcpy(s, "one of");
+         else if (nb == ni)
+            strcpy(s, "all of");
+         else
+            sprintf(s, "%d of", nb);
+         xprintf("%d integer variable%s, %s which %s binary\n",
+            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
+      }
+#if 1 /* 28/V-2010 */
+      if (parm->alien)
+      {  /* use alien integer optimizer */
+         ret = _glp_intopt1(P, parm);
+         goto done;
+      }
+#endif
+      if (!parm->presolve)
+         ret = solve_mip(P, parm);
+      else
+         ret = preprocess_and_solve_mip(P, parm);
+done: /* return to the application program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_iocp - initialize integer optimizer control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_iocp(glp_iocp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_iocp initializes control parameters, which are
+*  used by the integer optimizer, with default values.
+*
+*  Default values of the control parameters are stored in a glp_iocp
+*  structure, which the parameter parm points to. */
+
+void glp_init_iocp(glp_iocp *parm)
+{     parm->msg_lev = GLP_MSG_ALL;
+      parm->br_tech = GLP_BR_DTH;
+      parm->bt_tech = GLP_BT_BLB;
+      parm->tol_int = 1e-5;
+      parm->tol_obj = 1e-7;
+      parm->tm_lim = INT_MAX;
+      parm->out_frq = 5000;
+      parm->out_dly = 10000;
+      parm->cb_func = NULL;
+      parm->cb_info = NULL;
+      parm->cb_size = 0;
+      parm->pp_tech = GLP_PP_ALL;
+      parm->mip_gap = 0.0;
+      parm->mir_cuts = GLP_OFF;
+      parm->gmi_cuts = GLP_OFF;
+      parm->cov_cuts = GLP_OFF;
+      parm->clq_cuts = GLP_OFF;
+      parm->presolve = GLP_OFF;
+      parm->binarize = GLP_OFF;
+      parm->fp_heur = GLP_OFF;
+#if 1 /* 28/V-2010 */
+      parm->alien = GLP_OFF;
+#endif
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_status - retrieve status of MIP solution
+*
+*  SYNOPSIS
+*
+*  int glp_mip_status(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine lpx_mip_status reports the status of MIP solution found
+*  by the branch-and-bound solver as follows:
+*
+*  GLP_UNDEF  - MIP solution is undefined;
+*  GLP_OPT    - MIP solution is integer optimal;
+*  GLP_FEAS   - MIP solution is integer feasible but its optimality
+*               (or non-optimality) has not been proven, perhaps due to
+*               premature termination of the search;
+*  GLP_NOFEAS - problem has no integer feasible solution (proven by the
+*               solver). */
+
+int glp_mip_status(glp_prob *mip)
+{     int mip_stat = mip->mip_stat;
+      return mip_stat;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_obj_val - retrieve objective value (MIP solution)
+*
+*  SYNOPSIS
+*
+*  double glp_mip_obj_val(glp_prob *mip);
+*
+*  RETURNS
+*
+*  The routine glp_mip_obj_val returns value of the objective function
+*  for MIP solution. */
+
+double glp_mip_obj_val(glp_prob *mip)
+{     /*struct LPXCPS *cps = mip->cps;*/
+      double z;
+      z = mip->mip_obj;
+      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
+      return z;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_row_val - retrieve row value (MIP solution)
+*
+*  SYNOPSIS
+*
+*  double glp_mip_row_val(glp_prob *mip, int i);
+*
+*  RETURNS
+*
+*  The routine glp_mip_row_val returns value of the auxiliary variable
+*  associated with i-th row. */
+
+double glp_mip_row_val(glp_prob *mip, int i)
+{     /*struct LPXCPS *cps = mip->cps;*/
+      double mipx;
+      if (!(1 <= i && i <= mip->m))
+         xerror("glp_mip_row_val: i = %d; row number out of range\n", i)
+            ;
+      mipx = mip->row[i]->mipx;
+      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
+      return mipx;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mip_col_val - retrieve column value (MIP solution)
+*
+*  SYNOPSIS
+*
+*  double glp_mip_col_val(glp_prob *mip, int j);
+*
+*  RETURNS
+*
+*  The routine glp_mip_col_val returns value of the structural variable
+*  associated with j-th column. */
+
+double glp_mip_col_val(glp_prob *mip, int j)
+{     /*struct LPXCPS *cps = mip->cps;*/
+      double mipx;
+      if (!(1 <= j && j <= mip->n))
+         xerror("glp_mip_col_val: j = %d; column number out of range\n",
+            j);
+      mipx = mip->col[j]->mipx;
+      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
+      return mipx;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi10.c
===================================================================
--- deps/glpk/src/glpapi10.c	(revision 9)
+++ deps/glpk/src/glpapi10.c	(revision 9)
@@ -0,0 +1,282 @@
+/* glpapi10.c (solution checking routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+void _glp_check_kkt(glp_prob *P, int sol, int cond, double *_ae_max,
+      int *_ae_ind, double *_re_max, int *_re_ind)
+{     /* check feasibility and optimality conditions */
+      int m = P->m;
+      int n = P->n;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, ae_ind, re_ind;
+      double e, sp, sn, t, ae_max, re_max;
+      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
+         xerror("glp_check_kkt: sol = %d; invalid solution indicator\n",
+            sol);
+      if (!(cond == GLP_KKT_PE || cond == GLP_KKT_PB ||
+            cond == GLP_KKT_DE || cond == GLP_KKT_DB ||
+            cond == GLP_KKT_CS))
+         xerror("glp_check_kkt: cond = %d; invalid condition indicator "
+            "\n", cond);
+      ae_max = re_max = 0.0;
+      ae_ind = re_ind = 0;
+      if (cond == GLP_KKT_PE)
+      {  /* xR - A * xS = 0 */
+         for (i = 1; i <= m; i++)
+         {  row = P->row[i];
+            sp = sn = 0.0;
+            /* t := xR[i] */
+            if (sol == GLP_SOL)
+               t = row->prim;
+            else if (sol == GLP_IPT)
+               t = row->pval;
+            else if (sol == GLP_MIP)
+               t = row->mipx;
+            else
+               xassert(sol != sol);
+            if (t >= 0.0) sp += t; else sn -= t;
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            {  col = aij->col;
+               /* t := - a[i,j] * xS[j] */
+               if (sol == GLP_SOL)
+                  t = - aij->val * col->prim;
+               else if (sol == GLP_IPT)
+                  t = - aij->val * col->pval;
+               else if (sol == GLP_MIP)
+                  t = - aij->val * col->mipx;
+               else
+                  xassert(sol != sol);
+               if (t >= 0.0) sp += t; else sn -= t;
+            }
+            /* absolute error */
+            e = fabs(sp - sn);
+            if (ae_max < e)
+               ae_max = e, ae_ind = i;
+            /* relative error */
+            e /= (1.0 + sp + sn);
+            if (re_max < e)
+               re_max = e, re_ind = i;
+         }
+      }
+      else if (cond == GLP_KKT_PB)
+      {  /* lR <= xR <= uR */
+         for (i = 1; i <= m; i++)
+         {  row = P->row[i];
+            /* t := xR[i] */
+            if (sol == GLP_SOL)
+               t = row->prim;
+            else if (sol == GLP_IPT)
+               t = row->pval;
+            else if (sol == GLP_MIP)
+               t = row->mipx;
+            else
+               xassert(sol != sol);
+            /* check lower bound */
+            if (row->type == GLP_LO || row->type == GLP_DB ||
+                row->type == GLP_FX)
+            {  if (t < row->lb)
+               {  /* absolute error */
+                  e = row->lb - t;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = i;
+                  /* relative error */
+                  e /= (1.0 + fabs(row->lb));
+                  if (re_max < e)
+                     re_max = e, re_ind = i;
+               }
+            }
+            /* check upper bound */
+            if (row->type == GLP_UP || row->type == GLP_DB ||
+                row->type == GLP_FX)
+            {  if (t > row->ub)
+               {  /* absolute error */
+                  e = t - row->ub;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = i;
+                  /* relative error */
+                  e /= (1.0 + fabs(row->ub));
+                  if (re_max < e)
+                     re_max = e, re_ind = i;
+               }
+            }
+         }
+         /* lS <= xS <= uS */
+         for (j = 1; j <= n; j++)
+         {  col = P->col[j];
+            /* t := xS[j] */
+            if (sol == GLP_SOL)
+               t = col->prim;
+            else if (sol == GLP_IPT)
+               t = col->pval;
+            else if (sol == GLP_MIP)
+               t = col->mipx;
+            else
+               xassert(sol != sol);
+            /* check lower bound */
+            if (col->type == GLP_LO || col->type == GLP_DB ||
+                col->type == GLP_FX)
+            {  if (t < col->lb)
+               {  /* absolute error */
+                  e = col->lb - t;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = m+j;
+                  /* relative error */
+                  e /= (1.0 + fabs(col->lb));
+                  if (re_max < e)
+                     re_max = e, re_ind = m+j;
+               }
+            }
+            /* check upper bound */
+            if (col->type == GLP_UP || col->type == GLP_DB ||
+                col->type == GLP_FX)
+            {  if (t > col->ub)
+               {  /* absolute error */
+                  e = t - col->ub;
+                  if (ae_max < e)
+                     ae_max = e, ae_ind = m+j;
+                  /* relative error */
+                  e /= (1.0 + fabs(col->ub));
+                  if (re_max < e)
+                     re_max = e, re_ind = m+j;
+               }
+            }
+         }
+      }
+      else if (cond == GLP_KKT_DE)
+      {  /* A' * (lambdaR - cR) + (lambdaS - cS) = 0 */
+         for (j = 1; j <= n; j++)
+         {  col = P->col[j];
+            sp = sn = 0.0;
+            /* t := lambdaS[j] - cS[j] */
+            if (sol == GLP_SOL)
+               t = col->dual - col->coef;
+            else if (sol == GLP_IPT)
+               t = col->dval - col->coef;
+            else
+               xassert(sol != sol);
+            if (t >= 0.0) sp += t; else sn -= t;
+            for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+            {  row = aij->row;
+               /* t := a[i,j] * (lambdaR[i] - cR[i]) */
+               if (sol == GLP_SOL)
+                  t = aij->val * row->dual;
+               else if (sol == GLP_IPT)
+                  t = aij->val * row->dval;
+               else
+                  xassert(sol != sol);
+               if (t >= 0.0) sp += t; else sn -= t;
+            }
+            /* absolute error */
+            e = fabs(sp - sn);
+            if (ae_max < e)
+               ae_max = e, ae_ind = m+j;
+            /* relative error */
+            e /= (1.0 + sp + sn);
+            if (re_max < e)
+               re_max = e, re_ind = m+j;
+         }
+      }
+      else if (cond == GLP_KKT_DB)
+      {  /* check lambdaR */
+         for (i = 1; i <= m; i++)
+         {  row = P->row[i];
+            /* t := lambdaR[i] */
+            if (sol == GLP_SOL)
+               t = row->dual;
+            else if (sol == GLP_IPT)
+               t = row->dval;
+            else
+               xassert(sol != sol);
+            /* correct sign */
+            if (P->dir == GLP_MIN)
+               t = + t;
+            else if (P->dir == GLP_MAX)
+               t = - t;
+            else
+               xassert(P != P);
+            /* check for positivity */
+            if (row->type == GLP_FR || row->type == GLP_LO)
+            {  if (t < 0.0)
+               {  e = - t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = i;
+               }
+            }
+            /* check for negativity */
+            if (row->type == GLP_FR || row->type == GLP_UP)
+            {  if (t > 0.0)
+               {  e = + t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = i;
+               }
+            }
+         }
+         /* check lambdaS */
+         for (j = 1; j <= n; j++)
+         {  col = P->col[j];
+            /* t := lambdaS[j] */
+            if (sol == GLP_SOL)
+               t = col->dual;
+            else if (sol == GLP_IPT)
+               t = col->dval;
+            else
+               xassert(sol != sol);
+            /* correct sign */
+            if (P->dir == GLP_MIN)
+               t = + t;
+            else if (P->dir == GLP_MAX)
+               t = - t;
+            else
+               xassert(P != P);
+            /* check for positivity */
+            if (col->type == GLP_FR || col->type == GLP_LO)
+            {  if (t < 0.0)
+               {  e = - t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = m+j;
+               }
+            }
+            /* check for negativity */
+            if (col->type == GLP_FR || col->type == GLP_UP)
+            {  if (t > 0.0)
+               {  e = + t;
+                  if (ae_max < e)
+                     ae_max = re_max = e, ae_ind = re_ind = m+j;
+               }
+            }
+         }
+      }
+      else
+         xassert(cond != cond);
+      if (_ae_max != NULL) *_ae_max = ae_max;
+      if (_ae_ind != NULL) *_ae_ind = ae_ind;
+      if (_re_max != NULL) *_re_max = re_max;
+      if (_re_ind != NULL) *_re_ind = re_ind;
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi11.c
===================================================================
--- deps/glpk/src/glpapi11.c	(revision 9)
+++ deps/glpk/src/glpapi11.c	(revision 9)
@@ -0,0 +1,1217 @@
+/* glpapi11.c (utility routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+int glp_print_sol(glp_prob *P, const char *fname)
+{     /* write basic solution in printable format */
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j, t, ae_ind, re_ind, ret;
+      double ae_max, re_max;
+      xprintf("Writing basic solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%-12s%s\n", "Problem:",
+         P->name == NULL ? "" : P->name);
+      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
+      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+      t = glp_get_status(P);
+      xfprintf(fp, "%-12s%s\n", "Status:",
+         t == GLP_OPT    ? "OPTIMAL" :
+         t == GLP_FEAS   ? "FEASIBLE" :
+         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
+         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" :
+         t == GLP_UNBND  ? "UNBOUNDED" :
+         t == GLP_UNDEF  ? "UNDEFINED" : "???");
+      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+         P->obj == NULL ? "" : P->obj,
+         P->obj == NULL ? "" : " = ", P->obj_val,
+         P->dir == GLP_MIN ? "MINimum" :
+         P->dir == GLP_MAX ? "MAXimum" : "???");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No.   Row name   St   Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------ -- ------------- ------------- "
+         "------------- -------------\n");
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         xfprintf(fp, "%6d ", i);
+         if (row->name == NULL || strlen(row->name) <= 12)
+            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+         else
+            xfprintf(fp, "%s\n%20s", row->name, "");
+         xfprintf(fp, "%s ",
+            row->stat == GLP_BS ? "B " :
+            row->stat == GLP_NL ? "NL" :
+            row->stat == GLP_NU ? "NU" :
+            row->stat == GLP_NF ? "NF" :
+            row->stat == GLP_NS ? "NS" : "??");
+         xfprintf(fp, "%13.6g ",
+            fabs(row->prim) <= 1e-9 ? 0.0 : row->prim);
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", row->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (row->type == GLP_UP || row->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", row->ub);
+         else
+            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+         if (row->stat != GLP_BS)
+         {  if (fabs(row->dual) <= 1e-9)
+               xfprintf(fp, "%13s", "< eps");
+            else
+               xfprintf(fp, "%13.6g ", row->dual);
+         }
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No. Column name  St   Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------ -- ------------- ------------- "
+         "------------- -------------\n");
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         xfprintf(fp, "%6d ", j);
+         if (col->name == NULL || strlen(col->name) <= 12)
+            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+         else
+            xfprintf(fp, "%s\n%20s", col->name, "");
+         xfprintf(fp, "%s ",
+            col->stat == GLP_BS ? "B " :
+            col->stat == GLP_NL ? "NL" :
+            col->stat == GLP_NU ? "NU" :
+            col->stat == GLP_NF ? "NF" :
+            col->stat == GLP_NS ? "NS" : "??");
+         xfprintf(fp, "%13.6g ",
+            fabs(col->prim) <= 1e-9 ? 0.0 : col->prim);
+         if (col->type == GLP_LO || col->type == GLP_DB ||
+             col->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", col->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (col->type == GLP_UP || col->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", col->ub);
+         else
+            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+         if (col->stat != GLP_BS)
+         {  if (fabs(col->dual) <= 1e-9)
+               xfprintf(fp, "%13s", "< eps");
+            else
+               xfprintf(fp, "%13.6g ", col->dual);
+         }
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+         ae_max, ae_ind);
+      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
+         re_max, re_ind);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
+            "E");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
+         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
+         re_max, re_ind == 0 ? 0 : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
+            ;
+      xfprintf(fp, "\n");
+      xfprintf(fp, "End of output\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_sol - read basic solution from text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_sol(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_sol reads basic solution from a text file whose
+*  name is specified by the parameter fname into the problem object.
+*
+*  For the file format see description of the routine glp_write_sol.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero. */
+
+int glp_read_sol(glp_prob *lp, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int i, j, k, ret = 0;
+      xprintf("Reading basic solution from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      /* number of rows, number of columns */
+      k = glp_sdf_read_int(data);
+      if (k != lp->m)
+         glp_sdf_error(data, "wrong number of rows\n");
+      k = glp_sdf_read_int(data);
+      if (k != lp->n)
+         glp_sdf_error(data, "wrong number of columns\n");
+      /* primal status, dual status, objective value */
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
+            k == GLP_NOFEAS))
+         glp_sdf_error(data, "invalid primal status\n");
+      lp->pbs_stat = k;
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS ||
+            k == GLP_NOFEAS))
+         glp_sdf_error(data, "invalid dual status\n");
+      lp->dbs_stat = k;
+      lp->obj_val = glp_sdf_read_num(data);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* status, primal value, dual value */
+         k = glp_sdf_read_int(data);
+         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
+               k == GLP_NF || k == GLP_NS))
+            glp_sdf_error(data, "invalid row status\n");
+         glp_set_row_stat(lp, i, k);
+         row->prim = glp_sdf_read_num(data);
+         row->dual = glp_sdf_read_num(data);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* status, primal value, dual value */
+         k = glp_sdf_read_int(data);
+         if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU ||
+               k == GLP_NF || k == GLP_NS))
+            glp_sdf_error(data, "invalid column status\n");
+         glp_set_col_stat(lp, j, k);
+         col->prim = glp_sdf_read_num(data);
+         col->dual = glp_sdf_read_num(data);
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+done: if (ret) lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+      if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_sol - write basic solution to text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_sol(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_sol writes the current basic solution to a
+*  text file whose name is specified by the parameter fname. This file
+*  can be read back with the routine glp_read_sol.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine glp_write_sol is a plain text file,
+*  which contains the following information:
+*
+*     m n
+*     p_stat d_stat obj_val
+*     r_stat[1] r_prim[1] r_dual[1]
+*     . . .
+*     r_stat[m] r_prim[m] r_dual[m]
+*     c_stat[1] c_prim[1] c_dual[1]
+*     . . .
+*     c_stat[n] c_prim[n] c_dual[n]
+*
+*  where:
+*  m is the number of rows (auxiliary variables);
+*  n is the number of columns (structural variables);
+*  p_stat is the primal status of the basic solution (GLP_UNDEF = 1,
+*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
+*  d_stat is the dual status of the basic solution (GLP_UNDEF = 1,
+*     GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4);
+*  obj_val is the objective value;
+*  r_stat[i], i = 1,...,m, is the status of i-th row (GLP_BS = 1,
+*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
+*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
+*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
+*  c_stat[j], j = 1,...,n, is the status of j-th column (GLP_BS = 1,
+*     GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5);
+*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
+*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
+
+int glp_write_sol(glp_prob *lp, const char *fname)
+{     XFILE *fp;
+      int i, j, ret = 0;
+      xprintf("Writing basic solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns */
+      xfprintf(fp, "%d %d\n", lp->m, lp->n);
+      /* primal status, dual status, objective value */
+      xfprintf(fp, "%d %d %.*g\n", lp->pbs_stat, lp->dbs_stat, DBL_DIG,
+         lp->obj_val);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* status, primal value, dual value */
+         xfprintf(fp, "%d %.*g %.*g\n", row->stat, DBL_DIG, row->prim,
+            DBL_DIG, row->dual);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* status, primal value, dual value */
+         xfprintf(fp, "%d %.*g %.*g\n", col->stat, DBL_DIG, col->prim,
+            DBL_DIG, col->dual);
+      }
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/**********************************************************************/
+
+static char *format(char buf[13+1], double x)
+{     /* format floating-point number in MPS/360-like style */
+      if (x == -DBL_MAX)
+         strcpy(buf, "         -Inf");
+      else if (x == +DBL_MAX)
+         strcpy(buf, "         +Inf");
+      else if (fabs(x) <= 999999.99998)
+      {  sprintf(buf, "%13.5f", x);
+#if 1
+         if (strcmp(buf, "      0.00000") == 0 ||
+             strcmp(buf, "     -0.00000") == 0)
+            strcpy(buf, "       .     ");
+         else if (memcmp(buf, "      0.", 8) == 0)
+            memcpy(buf, "       .", 8);
+         else if (memcmp(buf, "     -0.", 8) == 0)
+            memcpy(buf, "      -.", 8);
+#endif
+      }
+      else
+         sprintf(buf, "%13.6g", x);
+      return buf;
+}
+
+int glp_print_ranges(glp_prob *P, int len, const int list[],
+      int flags, const char *fname)
+{     /* print sensitivity analysis report */
+      XFILE *fp = NULL;
+      GLPROW *row;
+      GLPCOL *col;
+      int m, n, pass, k, t, numb, type, stat, var1, var2, count, page,
+         ret;
+      double lb, ub, slack, coef, prim, dual, value1, value2, coef1,
+         coef2, obj1, obj2;
+      const char *name, *limit;
+      char buf[13+1];
+      /* sanity checks */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_print_ranges: P = %p; invalid problem object\n",
+            P);
+      m = P->m, n = P->n;
+      if (len < 0)
+         xerror("glp_print_ranges: len = %d; invalid list length\n",
+            len);
+      if (len > 0)
+      {  if (list == NULL)
+            xerror("glp_print_ranges: list = %p: invalid parameter\n",
+               list);
+         for (t = 1; t <= len; t++)
+         {  k = list[t];
+            if (!(1 <= k && k <= m+n))
+               xerror("glp_print_ranges: list[%d] = %d; row/column numb"
+                  "er out of range\n", t, k);
+         }
+      }
+      if (flags != 0)
+         xerror("glp_print_ranges: flags = %d; invalid parameter\n",
+            flags);
+      if (fname == NULL)
+         xerror("glp_print_ranges: fname = %p; invalid parameter\n",
+            fname);
+      if (glp_get_status(P) != GLP_OPT)
+      {  xprintf("glp_print_ranges: optimal basic solution required\n");
+         ret = 1;
+         goto done;
+      }
+      if (!glp_bf_exists(P))
+      {  xprintf("glp_print_ranges: basis factorization required\n");
+         ret = 2;
+         goto done;
+      }
+      /* start reporting */
+      xprintf("Write sensitivity analysis report to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 3;
+         goto done;
+      }
+      page = count = 0;
+      for (pass = 1; pass <= 2; pass++)
+      for (t = 1; t <= (len == 0 ? m+n : len); t++)
+      {  if (t == 1) count = 0;
+         k = (len == 0 ? t : list[t]);
+         if (pass == 1 && k > m || pass == 2 && k <= m)
+            continue;
+         if (count == 0)
+         {  xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa"
+               "ge%4d\n", glp_version(), "", ++page);
+            xfprintf(fp, "\n");
+            xfprintf(fp, "%-12s%s\n", "Problem:",
+               P->name == NULL ? "" : P->name);
+            xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+               P->obj == NULL ? "" : P->obj,
+               P->obj == NULL ? "" : " = ", P->obj_val,
+               P->dir == GLP_MIN ? "MINimum" :
+               P->dir == GLP_MAX ? "MAXimum" : "???");
+            xfprintf(fp, "\n");
+            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s "
+               "%s\n", "No.", pass == 1 ? "Row name" : "Column name",
+               "St", "Activity", pass == 1 ? "Slack" : "Obj coef",
+               "Lower bound", "Activity", "Obj coef", "Obj value at",
+               "Limiting");
+            xfprintf(fp, "%6s %-12s %2s %13s %13s %13s  %13s %13s %13s "
+               "%s\n", "", "", "", "", "Marginal", "Upper bound",
+               "range", "range", "break point", "variable");
+            xfprintf(fp, "------ ------------ -- ------------- --------"
+               "----- -------------  ------------- ------------- ------"
+               "------- ------------\n");
+         }
+         if (pass == 1)
+         {  numb = k;
+            xassert(1 <= numb && numb <= m);
+            row = P->row[numb];
+            name = row->name;
+            type = row->type;
+            lb = glp_get_row_lb(P, numb);
+            ub = glp_get_row_ub(P, numb);
+            coef = 0.0;
+            stat = row->stat;
+            prim = row->prim;
+            if (type == GLP_FR)
+               slack = - prim;
+            else if (type == GLP_LO)
+               slack = lb - prim;
+            else if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+               slack = ub - prim;
+            dual = row->dual;
+         }
+         else
+         {  numb = k - m;
+            xassert(1 <= numb && numb <= n);
+            col = P->col[numb];
+            name = col->name;
+            lb = glp_get_col_lb(P, numb);
+            ub = glp_get_col_ub(P, numb);
+            coef = col->coef;
+            stat = col->stat;
+            prim = col->prim;
+            slack = 0.0;
+            dual = col->dual;
+         }
+         if (stat != GLP_BS)
+         {  glp_analyze_bound(P, k, &value1, &var1, &value2, &var2);
+            if (stat == GLP_NF)
+               coef1 = coef2 = coef;
+            else if (stat == GLP_NS)
+               coef1 = -DBL_MAX, coef2 = +DBL_MAX;
+            else if (stat == GLP_NL && P->dir == GLP_MIN ||
+                     stat == GLP_NU && P->dir == GLP_MAX)
+               coef1 = coef - dual, coef2 = +DBL_MAX;
+            else
+               coef1 = -DBL_MAX, coef2 = coef - dual;
+            if (value1 == -DBL_MAX)
+            {  if (dual < -1e-9)
+                  obj1 = +DBL_MAX;
+               else if (dual > +1e-9)
+                  obj1 = -DBL_MAX;
+               else
+                  obj1 = P->obj_val;
+            }
+            else
+               obj1 = P->obj_val + dual * (value1 - prim);
+            if (value2 == +DBL_MAX)
+            {  if (dual < -1e-9)
+                  obj2 = -DBL_MAX;
+               else if (dual > +1e-9)
+                  obj2 = +DBL_MAX;
+               else
+                  obj2 = P->obj_val;
+            }
+            else
+               obj2 = P->obj_val + dual * (value2 - prim);
+         }
+         else
+         {  glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2,
+               &var2, &value2);
+            if (coef1 == -DBL_MAX)
+            {  if (prim < -1e-9)
+                  obj1 = +DBL_MAX;
+               else if (prim > +1e-9)
+                  obj1 = -DBL_MAX;
+               else
+                  obj1 = P->obj_val;
+            }
+            else
+               obj1 = P->obj_val + (coef1 - coef) * prim;
+            if (coef2 == +DBL_MAX)
+            {  if (prim < -1e-9)
+                  obj2 = -DBL_MAX;
+               else if (prim > +1e-9)
+                  obj2 = +DBL_MAX;
+               else
+                  obj2 = P->obj_val;
+            }
+            else
+               obj2 = P->obj_val + (coef2 - coef) * prim;
+         }
+         /*** first line ***/
+         /* row/column number */
+         xfprintf(fp, "%6d", numb);
+         /* row/column name */
+         xfprintf(fp, " %-12.12s", name == NULL ? "" : name);
+         if (name != NULL && strlen(name) > 12)
+            xfprintf(fp, "%s\n%6s %12s", name+12, "", "");
+         /* row/column status */
+         xfprintf(fp, " %2s",
+            stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" :
+            stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" :
+            stat == GLP_NS ? "NS" : "??");
+         /* row/column activity */
+         xfprintf(fp, " %s", format(buf, prim));
+         /* row slack, column objective coefficient */
+         xfprintf(fp, " %s", format(buf, k <= m ? slack : coef));
+         /* row/column lower bound */
+         xfprintf(fp, " %s", format(buf, lb));
+         /* row/column activity range */
+         xfprintf(fp, "  %s", format(buf, value1));
+         /* row/column objective coefficient range */
+         xfprintf(fp, " %s", format(buf, coef1));
+         /* objective value at break point */
+         xfprintf(fp, " %s", format(buf, obj1));
+         /* limiting variable name */
+         if (var1 != 0)
+         {  if (var1 <= m)
+               limit = glp_get_row_name(P, var1);
+            else
+               limit = glp_get_col_name(P, var1 - m);
+            if (limit != NULL)
+               xfprintf(fp, " %s", limit);
+         }
+         xfprintf(fp, "\n");
+         /*** second line ***/
+         xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", "");
+         /* row/column reduced cost */
+         xfprintf(fp, " %s", format(buf, dual));
+         /* row/column upper bound */
+         xfprintf(fp, " %s", format(buf, ub));
+         /* row/column activity range */
+         xfprintf(fp, "  %s", format(buf, value2));
+         /* row/column objective coefficient range */
+         xfprintf(fp, " %s", format(buf, coef2));
+         /* objective value at break point */
+         xfprintf(fp, " %s", format(buf, obj2));
+         /* limiting variable name */
+         if (var2 != 0)
+         {  if (var2 <= m)
+               limit = glp_get_row_name(P, var2);
+            else
+               limit = glp_get_col_name(P, var2 - m);
+            if (limit != NULL)
+               xfprintf(fp, " %s", limit);
+         }
+         xfprintf(fp, "\n");
+         xfprintf(fp, "\n");
+         /* print 10 items per page */
+         count = (count + 1) % 10;
+      }
+      xfprintf(fp, "End of report\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 4;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/**********************************************************************/
+
+int glp_print_ipt(glp_prob *P, const char *fname)
+{     /* write interior-point solution in printable format */
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j, t, ae_ind, re_ind, ret;
+      double ae_max, re_max;
+      xprintf("Writing interior-point solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%-12s%s\n", "Problem:",
+         P->name == NULL ? "" : P->name);
+      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+      xfprintf(fp, "%-12s%d\n", "Columns:", P->n);
+      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+      t = glp_ipt_status(P);
+      xfprintf(fp, "%-12s%s\n", "Status:",
+         t == GLP_OPT    ? "OPTIMAL" :
+         t == GLP_UNDEF  ? "UNDEFINED" :
+         t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" :
+         t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???");
+      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+         P->obj == NULL ? "" : P->obj,
+         P->obj == NULL ? "" : " = ", P->ipt_obj,
+         P->dir == GLP_MIN ? "MINimum" :
+         P->dir == GLP_MAX ? "MAXimum" : "???");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "------------- -------------\n");
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         xfprintf(fp, "%6d ", i);
+         if (row->name == NULL || strlen(row->name) <= 12)
+            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+         else
+            xfprintf(fp, "%s\n%20s", row->name, "");
+         xfprintf(fp, "%3s", "");
+         xfprintf(fp, "%13.6g ",
+            fabs(row->pval) <= 1e-9 ? 0.0 : row->pval);
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", row->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (row->type == GLP_UP || row->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", row->ub);
+         else
+            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+         if (fabs(row->dval) <= 1e-9)
+            xfprintf(fp, "%13s", "< eps");
+         else
+            xfprintf(fp, "%13.6g ", row->dval);
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
+         " Upper bound    Marginal\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "------------- -------------\n");
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         xfprintf(fp, "%6d ", j);
+         if (col->name == NULL || strlen(col->name) <= 12)
+            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+         else
+            xfprintf(fp, "%s\n%20s", col->name, "");
+         xfprintf(fp, "%3s", "");
+         xfprintf(fp, "%13.6g ",
+            fabs(col->pval) <= 1e-9 ? 0.0 : col->pval);
+         if (col->type == GLP_LO || col->type == GLP_DB ||
+             col->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", col->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (col->type == GLP_UP || col->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", col->ub);
+         else
+            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+         if (fabs(col->dval) <= 1e-9)
+            xfprintf(fp, "%13s", "< eps");
+         else
+            xfprintf(fp, "%13.6g ", col->dval);
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+         ae_max, ae_ind);
+      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
+         re_max, re_ind);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL"
+            "E");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n",
+         ae_max, ae_ind == 0 ? 0 : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on column %d\n",
+         re_max, re_ind == 0 ? 0 : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE")
+            ;
+      xfprintf(fp, "\n");
+      xfprintf(fp, "End of output\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_ipt - read interior-point solution from text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_ipt(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_ipt reads interior-point solution from a text
+*  file whose name is specified by the parameter fname into the problem
+*  object.
+*
+*  For the file format see description of the routine glp_write_ipt.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero. */
+
+int glp_read_ipt(glp_prob *lp, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int i, j, k, ret = 0;
+      xprintf("Reading interior-point solution from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      /* number of rows, number of columns */
+      k = glp_sdf_read_int(data);
+      if (k != lp->m)
+         glp_sdf_error(data, "wrong number of rows\n");
+      k = glp_sdf_read_int(data);
+      if (k != lp->n)
+         glp_sdf_error(data, "wrong number of columns\n");
+      /* solution status, objective value */
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_OPT))
+         glp_sdf_error(data, "invalid solution status\n");
+      lp->ipt_stat = k;
+      lp->ipt_obj = glp_sdf_read_num(data);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* primal value, dual value */
+         row->pval = glp_sdf_read_num(data);
+         row->dval = glp_sdf_read_num(data);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* primal value, dual value */
+         col->pval = glp_sdf_read_num(data);
+         col->dval = glp_sdf_read_num(data);
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+done: if (ret) lp->ipt_stat = GLP_UNDEF;
+      if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_ipt - write interior-point solution to text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_ipt(glp_prob *lp, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_ipt writes the current interior-point solution
+*  to a text file whose name is specified by the parameter fname. This
+*  file can be read back with the routine glp_read_ipt.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine glp_write_ipt is a plain text file,
+*  which contains the following information:
+*
+*     m n
+*     stat obj_val
+*     r_prim[1] r_dual[1]
+*     . . .
+*     r_prim[m] r_dual[m]
+*     c_prim[1] c_dual[1]
+*     . . .
+*     c_prim[n] c_dual[n]
+*
+*  where:
+*  m is the number of rows (auxiliary variables);
+*  n is the number of columns (structural variables);
+*  stat is the solution status (GLP_UNDEF = 1 or GLP_OPT = 5);
+*  obj_val is the objective value;
+*  r_prim[i], i = 1,...,m, is the primal value of i-th row;
+*  r_dual[i], i = 1,...,m, is the dual value of i-th row;
+*  c_prim[j], j = 1,...,n, is the primal value of j-th column;
+*  c_dual[j], j = 1,...,n, is the dual value of j-th column. */
+
+int glp_write_ipt(glp_prob *lp, const char *fname)
+{     XFILE *fp;
+      int i, j, ret = 0;
+      xprintf("Writing interior-point solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns */
+      xfprintf(fp, "%d %d\n", lp->m, lp->n);
+      /* solution status, objective value */
+      xfprintf(fp, "%d %.*g\n", lp->ipt_stat, DBL_DIG, lp->ipt_obj);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= lp->m; i++)
+      {  GLPROW *row = lp->row[i];
+         /* primal value, dual value */
+         xfprintf(fp, "%.*g %.*g\n", DBL_DIG, row->pval, DBL_DIG,
+            row->dval);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= lp->n; j++)
+      {  GLPCOL *col = lp->col[j];
+         /* primal value, dual value */
+         xfprintf(fp, "%.*g %.*g\n", DBL_DIG, col->pval, DBL_DIG,
+            col->dval);
+      }
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", 2 + lp->m + lp->n);
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/**********************************************************************/
+
+int glp_print_mip(glp_prob *P, const char *fname)
+{     /* write MIP solution in printable format */
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j, t, ae_ind, re_ind, ret;
+      double ae_max, re_max;
+      xprintf("Writing MIP solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%-12s%s\n", "Problem:",
+         P->name == NULL ? "" : P->name);
+      xfprintf(fp, "%-12s%d\n", "Rows:", P->m);
+      xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:",
+         P->n, glp_get_num_int(P), glp_get_num_bin(P));
+      xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz);
+      t = glp_mip_status(P);
+      xfprintf(fp, "%-12s%s\n", "Status:",
+         t == GLP_OPT    ? "INTEGER OPTIMAL" :
+         t == GLP_FEAS   ? "INTEGER NON-OPTIMAL" :
+         t == GLP_NOFEAS ? "INTEGER EMPTY" :
+         t == GLP_UNDEF  ? "INTEGER UNDEFINED" : "???");
+      xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:",
+         P->obj == NULL ? "" : P->obj,
+         P->obj == NULL ? "" : " = ", P->mip_obj,
+         P->dir == GLP_MIN ? "MINimum" :
+         P->dir == GLP_MAX ? "MAXimum" : "???");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No.   Row name        Activity     Lower bound  "
+         " Upper bound\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "-------------\n");
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         xfprintf(fp, "%6d ", i);
+         if (row->name == NULL || strlen(row->name) <= 12)
+            xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name);
+         else
+            xfprintf(fp, "%s\n%20s", row->name, "");
+         xfprintf(fp, "%3s", "");
+         xfprintf(fp, "%13.6g ",
+            fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx);
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", row->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (row->type == GLP_UP || row->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", row->ub);
+         else
+            xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : "");
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "   No. Column name       Activity     Lower bound  "
+         " Upper bound\n");
+      xfprintf(fp, "------ ------------    ------------- ------------- "
+         "-------------\n");
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         xfprintf(fp, "%6d ", j);
+         if (col->name == NULL || strlen(col->name) <= 12)
+            xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name);
+         else
+            xfprintf(fp, "%s\n%20s", col->name, "");
+         xfprintf(fp, "%s  ",
+            col->kind == GLP_CV ? " " :
+            col->kind == GLP_IV ? "*" : "?");
+         xfprintf(fp, "%13.6g ",
+            fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx);
+         if (col->type == GLP_LO || col->type == GLP_DB ||
+             col->type == GLP_FX)
+            xfprintf(fp, "%13.6g ", col->lb);
+         else
+            xfprintf(fp, "%13s ", "");
+         if (col->type == GLP_UP || col->type == GLP_DB)
+            xfprintf(fp, "%13.6g ", col->ub);
+         else
+            xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : "");
+         xfprintf(fp, "\n");
+      }
+      xfprintf(fp, "\n");
+      xfprintf(fp, "Integer feasibility conditions:\n");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n",
+         ae_max, ae_ind);
+      xfprintf(fp, "        max.rel.err = %.2e on row %d\n",
+         re_max, re_ind);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG");
+      xfprintf(fp, "\n");
+      _glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n",
+            ae_max, ae_ind <= P->m ? "row" : "column",
+            ae_ind <= P->m ? ae_ind : ae_ind - P->m);
+      xfprintf(fp, "        max.rel.err = %.2e on %s %d\n",
+            re_max, re_ind <= P->m ? "row" : "column",
+            re_ind <= P->m ? re_ind : re_ind - P->m);
+      xfprintf(fp, "%8s%s\n", "",
+         re_max <= 1e-9 ? "High quality" :
+         re_max <= 1e-6 ? "Medium quality" :
+         re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE");
+      xfprintf(fp, "\n");
+      xfprintf(fp, "End of output\n");
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_mip - read MIP solution from text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_mip(glp_prob *mip, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_mip reads MIP solution from a text file whose
+*  name is specified by the parameter fname into the problem object.
+*
+*  For the file format see description of the routine glp_write_mip.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero. */
+
+int glp_read_mip(glp_prob *mip, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int i, j, k, ret = 0;
+      xprintf("Reading MIP solution from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      /* number of rows, number of columns */
+      k = glp_sdf_read_int(data);
+      if (k != mip->m)
+         glp_sdf_error(data, "wrong number of rows\n");
+      k = glp_sdf_read_int(data);
+      if (k != mip->n)
+         glp_sdf_error(data, "wrong number of columns\n");
+      /* solution status, objective value */
+      k = glp_sdf_read_int(data);
+      if (!(k == GLP_UNDEF || k == GLP_OPT || k == GLP_FEAS ||
+            k == GLP_NOFEAS))
+         glp_sdf_error(data, "invalid solution status\n");
+      mip->mip_stat = k;
+      mip->mip_obj = glp_sdf_read_num(data);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= mip->m; i++)
+      {  GLPROW *row = mip->row[i];
+         row->mipx = glp_sdf_read_num(data);
+      }
+      /* columns (structural variables) */
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         col->mipx = glp_sdf_read_num(data);
+         if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
+            glp_sdf_error(data, "non-integer column value");
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+done: if (ret) mip->mip_stat = GLP_UNDEF;
+      if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_mip - write MIP solution to text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_mip(glp_prob *mip, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_mip writes the current MIP solution to a text
+*  file whose name is specified by the parameter fname. This file can
+*  be read back with the routine glp_read_mip.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine glp_write_sol is a plain text file,
+*  which contains the following information:
+*
+*     m n
+*     stat obj_val
+*     r_val[1]
+*     . . .
+*     r_val[m]
+*     c_val[1]
+*     . . .
+*     c_val[n]
+*
+*  where:
+*  m is the number of rows (auxiliary variables);
+*  n is the number of columns (structural variables);
+*  stat is the solution status (GLP_UNDEF = 1, GLP_FEAS = 2,
+*     GLP_NOFEAS = 4, or GLP_OPT = 5);
+*  obj_val is the objective value;
+*  r_val[i], i = 1,...,m, is the value of i-th row;
+*  c_val[j], j = 1,...,n, is the value of j-th column. */
+
+int glp_write_mip(glp_prob *mip, const char *fname)
+{     XFILE *fp;
+      int i, j, ret = 0;
+      xprintf("Writing MIP solution to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns */
+      xfprintf(fp, "%d %d\n", mip->m, mip->n);
+      /* solution status, objective value */
+      xfprintf(fp, "%d %.*g\n", mip->mip_stat, DBL_DIG, mip->mip_obj);
+      /* rows (auxiliary variables) */
+      for (i = 1; i <= mip->m; i++)
+         xfprintf(fp, "%.*g\n", DBL_DIG, mip->row[i]->mipx);
+      /* columns (structural variables) */
+      for (j = 1; j <= mip->n; j++)
+         xfprintf(fp, "%.*g\n", DBL_DIG, mip->col[j]->mipx);
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", 2 + mip->m + mip->n);
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi12.c
===================================================================
--- deps/glpk/src/glpapi12.c	(revision 9)
+++ deps/glpk/src/glpapi12.c	(revision 9)
@@ -0,0 +1,2219 @@
+/* glpapi12.c (basis factorization and simplex tableau routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_bf_exists - check if the basis factorization exists
+*
+*  SYNOPSIS
+*
+*  int glp_bf_exists(glp_prob *lp);
+*
+*  RETURNS
+*
+*  If the basis factorization for the current basis associated with
+*  the specified problem object exists and therefore is available for
+*  computations, the routine glp_bf_exists returns non-zero. Otherwise
+*  the routine returns zero. */
+
+int glp_bf_exists(glp_prob *lp)
+{     int ret;
+      ret = (lp->m == 0 || lp->valid);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_factorize - compute the basis factorization
+*
+*  SYNOPSIS
+*
+*  int glp_factorize(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_factorize computes the basis factorization for the
+*  current basis associated with the specified problem object.
+*
+*  RETURNS
+*
+*  0  The basis factorization has been successfully computed.
+*
+*  GLP_EBADB
+*     The basis matrix is invalid, i.e. the number of basic (auxiliary
+*     and structural) variables differs from the number of rows in the
+*     problem object.
+*
+*  GLP_ESING
+*     The basis matrix is singular within the working precision.
+*
+*  GLP_ECOND
+*     The basis matrix is ill-conditioned. */
+
+static int b_col(void *info, int j, int ind[], double val[])
+{     glp_prob *lp = info;
+      int m = lp->m;
+      GLPAIJ *aij;
+      int k, len;
+      xassert(1 <= j && j <= m);
+      /* determine the ordinal number of basic auxiliary or structural
+         variable x[k] corresponding to basic variable xB[j] */
+      k = lp->head[j];
+      /* build j-th column of the basic matrix, which is k-th column of
+         the scaled augmented matrix (I | -R*A*S) */
+      if (k <= m)
+      {  /* x[k] is auxiliary variable */
+         len = 1;
+         ind[1] = k;
+         val[1] = 1.0;
+      }
+      else
+      {  /* x[k] is structural variable */
+         len = 0;
+         for (aij = lp->col[k-m]->ptr; aij != NULL; aij = aij->c_next)
+         {  len++;
+            ind[len] = aij->row->i;
+            val[len] = - aij->row->rii * aij->val * aij->col->sjj;
+         }
+      }
+      return len;
+}
+
+static void copy_bfcp(glp_prob *lp);
+
+int glp_factorize(glp_prob *lp)
+{     int m = lp->m;
+      int n = lp->n;
+      GLPROW **row = lp->row;
+      GLPCOL **col = lp->col;
+      int *head = lp->head;
+      int j, k, stat, ret;
+      /* invalidate the basis factorization */
+      lp->valid = 0;
+      /* build the basis header */
+      j = 0;
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  stat = row[k]->stat;
+            row[k]->bind = 0;
+         }
+         else
+         {  stat = col[k-m]->stat;
+            col[k-m]->bind = 0;
+         }
+         if (stat == GLP_BS)
+         {  j++;
+            if (j > m)
+            {  /* too many basic variables */
+               ret = GLP_EBADB;
+               goto fini;
+            }
+            head[j] = k;
+            if (k <= m)
+               row[k]->bind = j;
+            else
+               col[k-m]->bind = j;
+         }
+      }
+      if (j < m)
+      {  /* too few basic variables */
+         ret = GLP_EBADB;
+         goto fini;
+      }
+      /* try to factorize the basis matrix */
+      if (m > 0)
+      {  if (lp->bfd == NULL)
+         {  lp->bfd = bfd_create_it();
+            copy_bfcp(lp);
+         }
+         switch (bfd_factorize(lp->bfd, m, lp->head, b_col, lp))
+         {  case 0:
+               /* ok */
+               break;
+            case BFD_ESING:
+               /* singular matrix */
+               ret = GLP_ESING;
+               goto fini;
+            case BFD_ECOND:
+               /* ill-conditioned matrix */
+               ret = GLP_ECOND;
+               goto fini;
+            default:
+               xassert(lp != lp);
+         }
+         lp->valid = 1;
+      }
+      /* factorization successful */
+      ret = 0;
+fini: /* bring the return code to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_bf_updated - check if the basis factorization has been updated
+*
+*  SYNOPSIS
+*
+*  int glp_bf_updated(glp_prob *lp);
+*
+*  RETURNS
+*
+*  If the basis factorization has been just computed from scratch, the
+*  routine glp_bf_updated returns zero. Otherwise, if the factorization
+*  has been updated one or more times, the routine returns non-zero. */
+
+int glp_bf_updated(glp_prob *lp)
+{     int cnt;
+      if (!(lp->m == 0 || lp->valid))
+         xerror("glp_bf_update: basis factorization does not exist\n");
+#if 0 /* 15/XI-2009 */
+      cnt = (lp->m == 0 ? 0 : lp->bfd->upd_cnt);
+#else
+      cnt = (lp->m == 0 ? 0 : bfd_get_count(lp->bfd));
+#endif
+      return cnt;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_bfcp - retrieve basis factorization control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_bfcp retrieves control parameters, which are
+*  used on computing and updating the basis factorization associated
+*  with the specified problem object.
+*
+*  Current values of control parameters are stored by the routine in
+*  a glp_bfcp structure, which the parameter parm points to. */
+
+void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm)
+{     glp_bfcp *bfcp = lp->bfcp;
+      if (bfcp == NULL)
+      {  parm->type = GLP_BF_FT;
+         parm->lu_size = 0;
+         parm->piv_tol = 0.10;
+         parm->piv_lim = 4;
+         parm->suhl = GLP_ON;
+         parm->eps_tol = 1e-15;
+         parm->max_gro = 1e+10;
+         parm->nfs_max = 100;
+         parm->upd_tol = 1e-6;
+         parm->nrs_max = 100;
+         parm->rs_size = 0;
+      }
+      else
+         memcpy(parm, bfcp, sizeof(glp_bfcp));
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_bfcp - change basis factorization control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_bfcp changes control parameters, which are used
+*  by internal GLPK routines in computing and updating the basis
+*  factorization associated with the specified problem object.
+*
+*  New values of the control parameters should be passed in a structure
+*  glp_bfcp, which the parameter parm points to.
+*
+*  The parameter parm can be specified as NULL, in which case all
+*  control parameters are reset to their default values. */
+
+#if 0 /* 15/XI-2009 */
+static void copy_bfcp(glp_prob *lp)
+{     glp_bfcp _parm, *parm = &_parm;
+      BFD *bfd = lp->bfd;
+      glp_get_bfcp(lp, parm);
+      xassert(bfd != NULL);
+      bfd->type = parm->type;
+      bfd->lu_size = parm->lu_size;
+      bfd->piv_tol = parm->piv_tol;
+      bfd->piv_lim = parm->piv_lim;
+      bfd->suhl = parm->suhl;
+      bfd->eps_tol = parm->eps_tol;
+      bfd->max_gro = parm->max_gro;
+      bfd->nfs_max = parm->nfs_max;
+      bfd->upd_tol = parm->upd_tol;
+      bfd->nrs_max = parm->nrs_max;
+      bfd->rs_size = parm->rs_size;
+      return;
+}
+#else
+static void copy_bfcp(glp_prob *lp)
+{     glp_bfcp _parm, *parm = &_parm;
+      glp_get_bfcp(lp, parm);
+      bfd_set_parm(lp->bfd, parm);
+      return;
+}
+#endif
+
+void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm)
+{     glp_bfcp *bfcp = lp->bfcp;
+      if (parm == NULL)
+      {  /* reset to default values */
+         if (bfcp != NULL)
+            xfree(bfcp), lp->bfcp = NULL;
+      }
+      else
+      {  /* set to specified values */
+         if (bfcp == NULL)
+            bfcp = lp->bfcp = xmalloc(sizeof(glp_bfcp));
+         memcpy(bfcp, parm, sizeof(glp_bfcp));
+         if (!(bfcp->type == GLP_BF_FT || bfcp->type == GLP_BF_BG ||
+               bfcp->type == GLP_BF_GR))
+            xerror("glp_set_bfcp: type = %d; invalid parameter\n",
+               bfcp->type);
+         if (bfcp->lu_size < 0)
+            xerror("glp_set_bfcp: lu_size = %d; invalid parameter\n",
+               bfcp->lu_size);
+         if (!(0.0 < bfcp->piv_tol && bfcp->piv_tol < 1.0))
+            xerror("glp_set_bfcp: piv_tol = %g; invalid parameter\n",
+               bfcp->piv_tol);
+         if (bfcp->piv_lim < 1)
+            xerror("glp_set_bfcp: piv_lim = %d; invalid parameter\n",
+               bfcp->piv_lim);
+         if (!(bfcp->suhl == GLP_ON || bfcp->suhl == GLP_OFF))
+            xerror("glp_set_bfcp: suhl = %d; invalid parameter\n",
+               bfcp->suhl);
+         if (!(0.0 <= bfcp->eps_tol && bfcp->eps_tol <= 1e-6))
+            xerror("glp_set_bfcp: eps_tol = %g; invalid parameter\n",
+               bfcp->eps_tol);
+         if (bfcp->max_gro < 1.0)
+            xerror("glp_set_bfcp: max_gro = %g; invalid parameter\n",
+               bfcp->max_gro);
+         if (!(1 <= bfcp->nfs_max && bfcp->nfs_max <= 32767))
+            xerror("glp_set_bfcp: nfs_max = %d; invalid parameter\n",
+               bfcp->nfs_max);
+         if (!(0.0 < bfcp->upd_tol && bfcp->upd_tol < 1.0))
+            xerror("glp_set_bfcp: upd_tol = %g; invalid parameter\n",
+               bfcp->upd_tol);
+         if (!(1 <= bfcp->nrs_max && bfcp->nrs_max <= 32767))
+            xerror("glp_set_bfcp: nrs_max = %d; invalid parameter\n",
+               bfcp->nrs_max);
+         if (bfcp->rs_size < 0)
+            xerror("glp_set_bfcp: rs_size = %d; invalid parameter\n",
+               bfcp->nrs_max);
+         if (bfcp->rs_size == 0)
+            bfcp->rs_size = 20 * bfcp->nrs_max;
+      }
+      if (lp->bfd != NULL) copy_bfcp(lp);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_bhead - retrieve the basis header information
+*
+*  SYNOPSIS
+*
+*  int glp_get_bhead(glp_prob *lp, int k);
+*
+*  DESCRIPTION
+*
+*  The routine glp_get_bhead returns the basis header information for
+*  the current basis associated with the specified problem object.
+*
+*  RETURNS
+*
+*  If xB[k], 1 <= k <= m, is i-th auxiliary variable (1 <= i <= m), the
+*  routine returns i. Otherwise, if xB[k] is j-th structural variable
+*  (1 <= j <= n), the routine returns m+j. Here m is the number of rows
+*  and n is the number of columns in the problem object. */
+
+int glp_get_bhead(glp_prob *lp, int k)
+{     if (!(lp->m == 0 || lp->valid))
+         xerror("glp_get_bhead: basis factorization does not exist\n");
+      if (!(1 <= k && k <= lp->m))
+         xerror("glp_get_bhead: k = %d; index out of range\n", k);
+      return lp->head[k];
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_row_bind - retrieve row index in the basis header
+*
+*  SYNOPSIS
+*
+*  int glp_get_row_bind(glp_prob *lp, int i);
+*
+*  RETURNS
+*
+*  The routine glp_get_row_bind returns the index k of basic variable
+*  xB[k], 1 <= k <= m, which is i-th auxiliary variable, 1 <= i <= m,
+*  in the current basis associated with the specified problem object,
+*  where m is the number of rows. However, if i-th auxiliary variable
+*  is non-basic, the routine returns zero. */
+
+int glp_get_row_bind(glp_prob *lp, int i)
+{     if (!(lp->m == 0 || lp->valid))
+         xerror("glp_get_row_bind: basis factorization does not exist\n"
+            );
+      if (!(1 <= i && i <= lp->m))
+         xerror("glp_get_row_bind: i = %d; row number out of range\n",
+            i);
+      return lp->row[i]->bind;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_get_col_bind - retrieve column index in the basis header
+*
+*  SYNOPSIS
+*
+*  int glp_get_col_bind(glp_prob *lp, int j);
+*
+*  RETURNS
+*
+*  The routine glp_get_col_bind returns the index k of basic variable
+*  xB[k], 1 <= k <= m, which is j-th structural variable, 1 <= j <= n,
+*  in the current basis associated with the specified problem object,
+*  where m is the number of rows, n is the number of columns. However,
+*  if j-th structural variable is non-basic, the routine returns zero.*/
+
+int glp_get_col_bind(glp_prob *lp, int j)
+{     if (!(lp->m == 0 || lp->valid))
+         xerror("glp_get_col_bind: basis factorization does not exist\n"
+            );
+      if (!(1 <= j && j <= lp->n))
+         xerror("glp_get_col_bind: j = %d; column number out of range\n"
+            , j);
+      return lp->col[j]->bind;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  void glp_ftran(glp_prob *lp, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix corresponding to the
+*  current basis for the specified problem object, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  SCALING/UNSCALING
+*
+*  Let A~ = (I | -A) is the augmented constraint matrix of the original
+*  (unscaled) problem. In the scaled LP problem instead the matrix A the
+*  scaled matrix A" = R*A*S is actually used, so
+*
+*     A~" = (I | A") = (I | R*A*S) = (R*I*inv(R) | R*A*S) =
+*                                                                    (1)
+*         = R*(I | A)*S~ = R*A~*S~,
+*
+*  is the scaled augmented constraint matrix, where R and S are diagonal
+*  scaling matrices used to scale rows and columns of the matrix A, and
+*
+*     S~ = diag(inv(R) | S)                                          (2)
+*
+*  is an augmented diagonal scaling matrix.
+*
+*  By definition:
+*
+*     A~ = (B | N),                                                  (3)
+*
+*  where B is the basic matrix, which consists of basic columns of the
+*  augmented constraint matrix A~, and N is a matrix, which consists of
+*  non-basic columns of A~. From (1) it follows that:
+*
+*     A~" = (B" | N") = (R*B*SB | R*N*SN),                           (4)
+*
+*  where SB and SN are parts of the augmented scaling matrix S~, which
+*  correspond to basic and non-basic variables, respectively. Therefore
+*
+*     B" = R*B*SB,                                                   (5)
+*
+*  which is the scaled basis matrix. */
+
+void glp_ftran(glp_prob *lp, double x[])
+{     int m = lp->m;
+      GLPROW **row = lp->row;
+      GLPCOL **col = lp->col;
+      int i, k;
+      /* B*x = b ===> (R*B*SB)*(inv(SB)*x) = R*b ===>
+         B"*x" = b", where b" = R*b, x = SB*x" */
+      if (!(m == 0 || lp->valid))
+         xerror("glp_ftran: basis factorization does not exist\n");
+      /* b" := R*b */
+      for (i = 1; i <= m; i++)
+         x[i] *= row[i]->rii;
+      /* x" := inv(B")*b" */
+      if (m > 0) bfd_ftran(lp->bfd, x);
+      /* x := SB*x" */
+      for (i = 1; i <= m; i++)
+      {  k = lp->head[i];
+         if (k <= m)
+            x[i] /= row[k]->rii;
+         else
+            x[i] *= col[k-m]->sjj;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  void glp_btran(glp_prob *lp, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix corresponding to the current basis for the specified problem
+*  problem object, x is the vector of unknowns to be computed, b is the
+*  vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  SCALING/UNSCALING
+*
+*  See comments to the routine glp_ftran. */
+
+void glp_btran(glp_prob *lp, double x[])
+{     int m = lp->m;
+      GLPROW **row = lp->row;
+      GLPCOL **col = lp->col;
+      int i, k;
+      /* B'*x = b ===> (SB*B'*R)*(inv(R)*x) = SB*b ===>
+         (B")'*x" = b", where b" = SB*b, x = R*x" */
+      if (!(m == 0 || lp->valid))
+         xerror("glp_btran: basis factorization does not exist\n");
+      /* b" := SB*b */
+      for (i = 1; i <= m; i++)
+      {  k = lp->head[i];
+         if (k <= m)
+            x[i] /= row[k]->rii;
+         else
+            x[i] *= col[k-m]->sjj;
+      }
+      /* x" := inv[(B")']*b" */
+      if (m > 0) bfd_btran(lp->bfd, x);
+      /* x := R*x" */
+      for (i = 1; i <= m; i++)
+         x[i] *= row[i]->rii;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_warm_up - "warm up" LP basis
+*
+*  SYNOPSIS
+*
+*  int glp_warm_up(glp_prob *P);
+*
+*  DESCRIPTION
+*
+*  The routine glp_warm_up "warms up" the LP basis for the specified
+*  problem object using current statuses assigned to rows and columns
+*  (that is, to auxiliary and structural variables).
+*
+*  This operation includes computing factorization of the basis matrix
+*  (if it does not exist), computing primal and dual components of basic
+*  solution, and determining the solution status.
+*
+*  RETURNS
+*
+*  0  The operation has been successfully performed.
+*
+*  GLP_EBADB
+*     The basis matrix is invalid, i.e. the number of basic (auxiliary
+*     and structural) variables differs from the number of rows in the
+*     problem object.
+*
+*  GLP_ESING
+*     The basis matrix is singular within the working precision.
+*
+*  GLP_ECOND
+*     The basis matrix is ill-conditioned. */
+
+int glp_warm_up(glp_prob *P)
+{     GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, type, ret;
+      double eps, temp, *work;
+      /* invalidate basic solution */
+      P->pbs_stat = P->dbs_stat = GLP_UNDEF;
+      P->obj_val = 0.0;
+      P->some = 0;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         row->prim = row->dual = 0.0;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         col->prim = col->dual = 0.0;
+      }
+      /* compute the basis factorization, if necessary */
+      if (!glp_bf_exists(P))
+      {  ret = glp_factorize(P);
+         if (ret != 0) goto done;
+      }
+      /* allocate working array */
+      work = xcalloc(1+P->m, sizeof(double));
+      /* determine and store values of non-basic variables, compute
+         vector (- N * xN) */
+      for (i = 1; i <= P->m; i++)
+         work[i] = 0.0;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->stat == GLP_BS)
+            continue;
+         else if (row->stat == GLP_NL)
+            row->prim = row->lb;
+         else if (row->stat == GLP_NU)
+            row->prim = row->ub;
+         else if (row->stat == GLP_NF)
+            row->prim = 0.0;
+         else if (row->stat == GLP_NS)
+            row->prim = row->lb;
+         else
+            xassert(row != row);
+         /* N[j] is i-th column of matrix (I|-A) */
+         work[i] -= row->prim;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat == GLP_BS)
+            continue;
+         else if (col->stat == GLP_NL)
+            col->prim = col->lb;
+         else if (col->stat == GLP_NU)
+            col->prim = col->ub;
+         else if (col->stat == GLP_NF)
+            col->prim = 0.0;
+         else if (col->stat == GLP_NS)
+            col->prim = col->lb;
+         else
+            xassert(col != col);
+         /* N[j] is (m+j)-th column of matrix (I|-A) */
+         if (col->prim != 0.0)
+         {  for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+               work[aij->row->i] += aij->val * col->prim;
+         }
+      }
+      /* compute vector of basic variables xB = - inv(B) * N * xN */
+      glp_ftran(P, work);
+      /* store values of basic variables, check primal feasibility */
+      P->pbs_stat = GLP_FEAS;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->stat != GLP_BS)
+            continue;
+         row->prim = work[row->bind];
+         type = row->type;
+         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(row->lb);
+            if (row->prim < row->lb - eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(row->ub);
+            if (row->prim > row->ub + eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat != GLP_BS)
+            continue;
+         col->prim = work[col->bind];
+         type = col->type;
+         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(col->lb);
+            if (col->prim < col->lb - eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+         {  eps = 1e-6 + 1e-9 * fabs(col->ub);
+            if (col->prim > col->ub + eps)
+               P->pbs_stat = GLP_INFEAS;
+         }
+      }
+      /* compute value of the objective function */
+      P->obj_val = P->c0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         P->obj_val += col->coef * col->prim;
+      }
+      /* build vector cB of objective coefficients at basic variables */
+      for (i = 1; i <= P->m; i++)
+         work[i] = 0.0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat == GLP_BS)
+            work[col->bind] = col->coef;
+      }
+      /* compute vector of simplex multipliers pi = inv(B') * cB */
+      glp_btran(P, work);
+      /* compute and store reduced costs of non-basic variables d[j] =
+         c[j] - N'[j] * pi, check dual feasibility */
+      P->dbs_stat = GLP_FEAS;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->stat == GLP_BS)
+         {  row->dual = 0.0;
+            continue;
+         }
+         /* N[j] is i-th column of matrix (I|-A) */
+         row->dual = - work[i];
+         type = row->type;
+         temp = (P->dir == GLP_MIN ? + row->dual : - row->dual);
+         if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
+             (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
+            P->dbs_stat = GLP_INFEAS;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->stat == GLP_BS)
+         {  col->dual = 0.0;
+            continue;
+         }
+         /* N[j] is (m+j)-th column of matrix (I|-A) */
+         col->dual = col->coef;
+         for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+            col->dual += aij->val * work[aij->row->i];
+         type = col->type;
+         temp = (P->dir == GLP_MIN ? + col->dual : - col->dual);
+         if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 ||
+             (type == GLP_FR || type == GLP_UP) && temp > +1e-5)
+            P->dbs_stat = GLP_INFEAS;
+      }
+      /* free working array */
+      xfree(work);
+      ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_eval_tab_row - compute row of the simplex tableau
+*
+*  SYNOPSIS
+*
+*  int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_eval_tab_row computes a row of the current simplex
+*  tableau for the basic variable, which is specified by the number k:
+*  if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
+*  x[k] is (k-m)-th structural variable, where m is number of rows, and
+*  n is number of columns. The current basis must be available.
+*
+*  The routine stores column indices and numerical values of non-zero
+*  elements of the computed row using sparse format to the locations
+*  ind[1], ..., ind[len] and val[1], ..., val[len], respectively, where
+*  0 <= len <= n is number of non-zeros returned on exit.
+*
+*  Element indices stored in the array ind have the same sense as the
+*  index k, i.e. indices 1 to m denote auxiliary variables and indices
+*  m+1 to m+n denote structural ones (all these variables are obviously
+*  non-basic by definition).
+*
+*  The computed row shows how the specified basic variable x[k] = xB[i]
+*  depends on non-basic variables:
+*
+*     xB[i] = alfa[i,1]*xN[1] + alfa[i,2]*xN[2] + ... + alfa[i,n]*xN[n],
+*
+*  where alfa[i,j] are elements of the simplex table row, xN[j] are
+*  non-basic (auxiliary and structural) variables.
+*
+*  RETURNS
+*
+*  The routine returns number of non-zero elements in the simplex table
+*  row stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  The system of equality constraints of the LP problem is:
+*
+*     xR = A * xS,                                                   (1)
+*
+*  where xR is the vector of auxliary variables, xS is the vector of
+*  structural variables, A is the matrix of constraint coefficients.
+*
+*  The system (1) can be written in homogenous form as follows:
+*
+*     A~ * x = 0,                                                    (2)
+*
+*  where A~ = (I | -A) is the augmented constraint matrix (has m rows
+*  and m+n columns), x = (xR | xS) is the vector of all (auxiliary and
+*  structural) variables.
+*
+*  By definition for the current basis we have:
+*
+*     A~ = (B | N),                                                  (3)
+*
+*  where B is the basis matrix. Thus, the system (2) can be written as:
+*
+*     B * xB + N * xN = 0.                                           (4)
+*
+*  From (4) it follows that:
+*
+*     xB = A^ * xN,                                                  (5)
+*
+*  where the matrix
+*
+*     A^ = - inv(B) * N                                              (6)
+*
+*  is called the simplex table.
+*
+*  It is understood that i-th row of the simplex table is:
+*
+*     e * A^ = - e * inv(B) * N,                                     (7)
+*
+*  where e is a unity vector with e[i] = 1.
+*
+*  To compute i-th row of the simplex table the routine first computes
+*  i-th row of the inverse:
+*
+*     rho = inv(B') * e,                                             (8)
+*
+*  where B' is a matrix transposed to B, and then computes elements of
+*  i-th row of the simplex table as scalar products:
+*
+*     alfa[i,j] = - rho * N[j]   for all j,                          (9)
+*
+*  where N[j] is a column of the augmented constraint matrix A~, which
+*  corresponds to some non-basic auxiliary or structural variable. */
+
+int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[])
+{     int m = lp->m;
+      int n = lp->n;
+      int i, t, len, lll, *iii;
+      double alfa, *rho, *vvv;
+      if (!(m == 0 || lp->valid))
+         xerror("glp_eval_tab_row: basis factorization does not exist\n"
+            );
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_eval_tab_row: k = %d; variable number out of range"
+            , k);
+      /* determine xB[i] which corresponds to x[k] */
+      if (k <= m)
+         i = glp_get_row_bind(lp, k);
+      else
+         i = glp_get_col_bind(lp, k-m);
+      if (i == 0)
+         xerror("glp_eval_tab_row: k = %d; variable must be basic", k);
+      xassert(1 <= i && i <= m);
+      /* allocate working arrays */
+      rho = xcalloc(1+m, sizeof(double));
+      iii = xcalloc(1+m, sizeof(int));
+      vvv = xcalloc(1+m, sizeof(double));
+      /* compute i-th row of the inverse; see (8) */
+      for (t = 1; t <= m; t++) rho[t] = 0.0;
+      rho[i] = 1.0;
+      glp_btran(lp, rho);
+      /* compute i-th row of the simplex table */
+      len = 0;
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+         {  /* x[k] is auxiliary variable, so N[k] is a unity column */
+            if (glp_get_row_stat(lp, k) == GLP_BS) continue;
+            /* compute alfa[i,j]; see (9) */
+            alfa = - rho[k];
+         }
+         else
+         {  /* x[k] is structural variable, so N[k] is a column of the
+               original constraint matrix A with negative sign */
+            if (glp_get_col_stat(lp, k-m) == GLP_BS) continue;
+            /* compute alfa[i,j]; see (9) */
+            lll = glp_get_mat_col(lp, k-m, iii, vvv);
+            alfa = 0.0;
+            for (t = 1; t <= lll; t++) alfa += rho[iii[t]] * vvv[t];
+         }
+         /* store alfa[i,j] */
+         if (alfa != 0.0) len++, ind[len] = k, val[len] = alfa;
+      }
+      xassert(len <= n);
+      /* free working arrays */
+      xfree(rho);
+      xfree(iii);
+      xfree(vvv);
+      /* return to the calling program */
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_eval_tab_col - compute column of the simplex tableau
+*
+*  SYNOPSIS
+*
+*  int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_eval_tab_col computes a column of the current simplex
+*  table for the non-basic variable, which is specified by the number k:
+*  if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n,
+*  x[k] is (k-m)-th structural variable, where m is number of rows, and
+*  n is number of columns. The current basis must be available.
+*
+*  The routine stores row indices and numerical values of non-zero
+*  elements of the computed column using sparse format to the locations
+*  ind[1], ..., ind[len] and val[1], ..., val[len] respectively, where
+*  0 <= len <= m is number of non-zeros returned on exit.
+*
+*  Element indices stored in the array ind have the same sense as the
+*  index k, i.e. indices 1 to m denote auxiliary variables and indices
+*  m+1 to m+n denote structural ones (all these variables are obviously
+*  basic by the definition).
+*
+*  The computed column shows how basic variables depend on the specified
+*  non-basic variable x[k] = xN[j]:
+*
+*     xB[1] = ... + alfa[1,j]*xN[j] + ...
+*     xB[2] = ... + alfa[2,j]*xN[j] + ...
+*              . . . . . .
+*     xB[m] = ... + alfa[m,j]*xN[j] + ...
+*
+*  where alfa[i,j] are elements of the simplex table column, xB[i] are
+*  basic (auxiliary and structural) variables.
+*
+*  RETURNS
+*
+*  The routine returns number of non-zero elements in the simplex table
+*  column stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  As it was explained in comments to the routine glp_eval_tab_row (see
+*  above) the simplex table is the following matrix:
+*
+*     A^ = - inv(B) * N.                                             (1)
+*
+*  Therefore j-th column of the simplex table is:
+*
+*     A^ * e = - inv(B) * N * e = - inv(B) * N[j],                   (2)
+*
+*  where e is a unity vector with e[j] = 1, B is the basis matrix, N[j]
+*  is a column of the augmented constraint matrix A~, which corresponds
+*  to the given non-basic auxiliary or structural variable. */
+
+int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[])
+{     int m = lp->m;
+      int n = lp->n;
+      int t, len, stat;
+      double *col;
+      if (!(m == 0 || lp->valid))
+         xerror("glp_eval_tab_col: basis factorization does not exist\n"
+            );
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_eval_tab_col: k = %d; variable number out of range"
+            , k);
+      if (k <= m)
+         stat = glp_get_row_stat(lp, k);
+      else
+         stat = glp_get_col_stat(lp, k-m);
+      if (stat == GLP_BS)
+         xerror("glp_eval_tab_col: k = %d; variable must be non-basic",
+            k);
+      /* obtain column N[k] with negative sign */
+      col = xcalloc(1+m, sizeof(double));
+      for (t = 1; t <= m; t++) col[t] = 0.0;
+      if (k <= m)
+      {  /* x[k] is auxiliary variable, so N[k] is a unity column */
+         col[k] = -1.0;
+      }
+      else
+      {  /* x[k] is structural variable, so N[k] is a column of the
+            original constraint matrix A with negative sign */
+         len = glp_get_mat_col(lp, k-m, ind, val);
+         for (t = 1; t <= len; t++) col[ind[t]] = val[t];
+      }
+      /* compute column of the simplex table, which corresponds to the
+         specified non-basic variable x[k] */
+      glp_ftran(lp, col);
+      len = 0;
+      for (t = 1; t <= m; t++)
+      {  if (col[t] != 0.0)
+         {  len++;
+            ind[len] = glp_get_bhead(lp, t);
+            val[len] = col[t];
+         }
+      }
+      xfree(col);
+      /* return to the calling program */
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_transform_row - transform explicitly specified row
+*
+*  SYNOPSIS
+*
+*  int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_transform_row performs the same operation as the
+*  routine glp_eval_tab_row with exception that the row to be
+*  transformed is specified explicitly as a sparse vector.
+*
+*  The explicitly specified row may be thought as a linear form:
+*
+*     x = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],             (1)
+*
+*  where x is an auxiliary variable for this row, a[j] are coefficients
+*  of the linear form, x[m+j] are structural variables.
+*
+*  On entry column indices and numerical values of non-zero elements of
+*  the row should be stored in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], where len is the number of non-zero elements.
+*
+*  This routine uses the system of equality constraints and the current
+*  basis in order to express the auxiliary variable x in (1) through the
+*  current non-basic variables (as if the transformed row were added to
+*  the problem object and its auxiliary variable were basic), i.e. the
+*  resultant row has the form:
+*
+*     x = alfa[1]*xN[1] + alfa[2]*xN[2] + ... + alfa[n]*xN[n],       (2)
+*
+*  where xN[j] are non-basic (auxiliary or structural) variables, n is
+*  the number of columns in the LP problem object.
+*
+*  On exit the routine stores indices and numerical values of non-zero
+*  elements of the resultant row (2) in locations ind[1], ..., ind[len']
+*  and val[1], ..., val[len'], where 0 <= len' <= n is the number of
+*  non-zero elements in the resultant row returned by the routine. Note
+*  that indices (numbers) of non-basic variables stored in the array ind
+*  correspond to original ordinal numbers of variables: indices 1 to m
+*  mean auxiliary variables and indices m+1 to m+n mean structural ones.
+*
+*  RETURNS
+*
+*  The routine returns len', which is the number of non-zero elements in
+*  the resultant row stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  The explicitly specified row (1) is transformed in the same way as it
+*  were the objective function row.
+*
+*  From (1) it follows that:
+*
+*     x = aB * xB + aN * xN,                                         (3)
+*
+*  where xB is the vector of basic variables, xN is the vector of
+*  non-basic variables.
+*
+*  The simplex table, which corresponds to the current basis, is:
+*
+*     xB = [-inv(B) * N] * xN.                                       (4)
+*
+*  Therefore substituting xB from (4) to (3) we have:
+*
+*     x = aB * [-inv(B) * N] * xN + aN * xN =
+*                                                                    (5)
+*       = rho * (-N) * xN + aN * xN = alfa * xN,
+*
+*  where:
+*
+*     rho = inv(B') * aB,                                            (6)
+*
+*  and
+*
+*     alfa = aN + rho * (-N)                                         (7)
+*
+*  is the resultant row computed by the routine. */
+
+int glp_transform_row(glp_prob *P, int len, int ind[], double val[])
+{     int i, j, k, m, n, t, lll, *iii;
+      double alfa, *a, *aB, *rho, *vvv;
+      if (!glp_bf_exists(P))
+         xerror("glp_transform_row: basis factorization does not exist "
+            "\n");
+      m = glp_get_num_rows(P);
+      n = glp_get_num_cols(P);
+      /* unpack the row to be transformed to the array a */
+      a = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++) a[j] = 0.0;
+      if (!(0 <= len && len <= n))
+         xerror("glp_transform_row: len = %d; invalid row length\n",
+            len);
+      for (t = 1; t <= len; t++)
+      {  j = ind[t];
+         if (!(1 <= j && j <= n))
+            xerror("glp_transform_row: ind[%d] = %d; column index out o"
+               "f range\n", t, j);
+         if (val[t] == 0.0)
+            xerror("glp_transform_row: val[%d] = 0; zero coefficient no"
+               "t allowed\n", t);
+         if (a[j] != 0.0)
+            xerror("glp_transform_row: ind[%d] = %d; duplicate column i"
+               "ndices not allowed\n", t, j);
+         a[j] = val[t];
+      }
+      /* construct the vector aB */
+      aB = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  k = glp_get_bhead(P, i);
+         /* xB[i] is k-th original variable */
+         xassert(1 <= k && k <= m+n);
+         aB[i] = (k <= m ? 0.0 : a[k-m]);
+      }
+      /* solve the system B'*rho = aB to compute the vector rho */
+      rho = aB, glp_btran(P, rho);
+      /* compute coefficients at non-basic auxiliary variables */
+      len = 0;
+      for (i = 1; i <= m; i++)
+      {  if (glp_get_row_stat(P, i) != GLP_BS)
+         {  alfa = - rho[i];
+            if (alfa != 0.0)
+            {  len++;
+               ind[len] = i;
+               val[len] = alfa;
+            }
+         }
+      }
+      /* compute coefficients at non-basic structural variables */
+      iii = xcalloc(1+m, sizeof(int));
+      vvv = xcalloc(1+m, sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  if (glp_get_col_stat(P, j) != GLP_BS)
+         {  alfa = a[j];
+            lll = glp_get_mat_col(P, j, iii, vvv);
+            for (t = 1; t <= lll; t++) alfa += vvv[t] * rho[iii[t]];
+            if (alfa != 0.0)
+            {  len++;
+               ind[len] = m+j;
+               val[len] = alfa;
+            }
+         }
+      }
+      xassert(len <= n);
+      xfree(iii);
+      xfree(vvv);
+      xfree(aB);
+      xfree(a);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_transform_col - transform explicitly specified column
+*
+*  SYNOPSIS
+*
+*  int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_transform_col performs the same operation as the
+*  routine glp_eval_tab_col with exception that the column to be
+*  transformed is specified explicitly as a sparse vector.
+*
+*  The explicitly specified column may be thought as if it were added
+*  to the original system of equality constraints:
+*
+*     x[1] = a[1,1]*x[m+1] + ... + a[1,n]*x[m+n] + a[1]*x
+*     x[2] = a[2,1]*x[m+1] + ... + a[2,n]*x[m+n] + a[2]*x            (1)
+*        .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+*     x[m] = a[m,1]*x[m+1] + ... + a[m,n]*x[m+n] + a[m]*x
+*
+*  where x[i] are auxiliary variables, x[m+j] are structural variables,
+*  x is a structural variable for the explicitly specified column, a[i]
+*  are constraint coefficients for x.
+*
+*  On entry row indices and numerical values of non-zero elements of
+*  the column should be stored in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], where len is the number of non-zero elements.
+*
+*  This routine uses the system of equality constraints and the current
+*  basis in order to express the current basic variables through the
+*  structural variable x in (1) (as if the transformed column were added
+*  to the problem object and the variable x were non-basic), i.e. the
+*  resultant column has the form:
+*
+*     xB[1] = ... + alfa[1]*x
+*     xB[2] = ... + alfa[2]*x                                        (2)
+*        .  .  .  .  .  .
+*     xB[m] = ... + alfa[m]*x
+*
+*  where xB are basic (auxiliary and structural) variables, m is the
+*  number of rows in the problem object.
+*
+*  On exit the routine stores indices and numerical values of non-zero
+*  elements of the resultant column (2) in locations ind[1], ...,
+*  ind[len'] and val[1], ..., val[len'], where 0 <= len' <= m is the
+*  number of non-zero element in the resultant column returned by the
+*  routine. Note that indices (numbers) of basic variables stored in
+*  the array ind correspond to original ordinal numbers of variables:
+*  indices 1 to m mean auxiliary variables and indices m+1 to m+n mean
+*  structural ones.
+*
+*  RETURNS
+*
+*  The routine returns len', which is the number of non-zero elements
+*  in the resultant column stored in the arrays ind and val.
+*
+*  BACKGROUND
+*
+*  The explicitly specified column (1) is transformed in the same way
+*  as any other column of the constraint matrix using the formula:
+*
+*     alfa = inv(B) * a,                                             (3)
+*
+*  where alfa is the resultant column computed by the routine. */
+
+int glp_transform_col(glp_prob *P, int len, int ind[], double val[])
+{     int i, m, t;
+      double *a, *alfa;
+      if (!glp_bf_exists(P))
+         xerror("glp_transform_col: basis factorization does not exist "
+            "\n");
+      m = glp_get_num_rows(P);
+      /* unpack the column to be transformed to the array a */
+      a = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) a[i] = 0.0;
+      if (!(0 <= len && len <= m))
+         xerror("glp_transform_col: len = %d; invalid column length\n",
+            len);
+      for (t = 1; t <= len; t++)
+      {  i = ind[t];
+         if (!(1 <= i && i <= m))
+            xerror("glp_transform_col: ind[%d] = %d; row index out of r"
+               "ange\n", t, i);
+         if (val[t] == 0.0)
+            xerror("glp_transform_col: val[%d] = 0; zero coefficient no"
+               "t allowed\n", t);
+         if (a[i] != 0.0)
+            xerror("glp_transform_col: ind[%d] = %d; duplicate row indi"
+               "ces not allowed\n", t, i);
+         a[i] = val[t];
+      }
+      /* solve the system B*a = alfa to compute the vector alfa */
+      alfa = a, glp_ftran(P, alfa);
+      /* store resultant coefficients */
+      len = 0;
+      for (i = 1; i <= m; i++)
+      {  if (alfa[i] != 0.0)
+         {  len++;
+            ind[len] = glp_get_bhead(P, i);
+            val[len] = alfa[i];
+         }
+      }
+      xfree(a);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_prim_rtest - perform primal ratio test
+*
+*  SYNOPSIS
+*
+*  int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+*     const double val[], int dir, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine glp_prim_rtest performs the primal ratio test using an
+*  explicitly specified column of the simplex table.
+*
+*  The current basic solution associated with the LP problem object
+*  must be primal feasible.
+*
+*  The explicitly specified column of the simplex table shows how the
+*  basic variables xB depend on some non-basic variable x (which is not
+*  necessarily presented in the problem object):
+*
+*     xB[1] = ... + alfa[1] * x + ...
+*     xB[2] = ... + alfa[2] * x + ...                                (*)
+*         .  .  .  .  .  .  .  .
+*     xB[m] = ... + alfa[m] * x + ...
+*
+*  The column (*) is specifed on entry to the routine using the sparse
+*  format. Ordinal numbers of basic variables xB[i] should be placed in
+*  locations ind[1], ..., ind[len], where ordinal number 1 to m denote
+*  auxiliary variables, and ordinal numbers m+1 to m+n denote structural
+*  variables. The corresponding non-zero coefficients alfa[i] should be
+*  placed in locations val[1], ..., val[len]. The arrays ind and val are
+*  not changed on exit.
+*
+*  The parameter dir specifies direction in which the variable x changes
+*  on entering the basis: +1 means increasing, -1 means decreasing.
+*
+*  The parameter eps is an absolute tolerance (small positive number)
+*  used by the routine to skip small alfa[j] of the row (*).
+*
+*  The routine determines which basic variable (among specified in
+*  ind[1], ..., ind[len]) should leave the basis in order to keep primal
+*  feasibility.
+*
+*  RETURNS
+*
+*  The routine glp_prim_rtest returns the index piv in the arrays ind
+*  and val corresponding to the pivot element chosen, 1 <= piv <= len.
+*  If the adjacent basic solution is primal unbounded and therefore the
+*  choice cannot be made, the routine returns zero.
+*
+*  COMMENTS
+*
+*  If the non-basic variable x is presented in the LP problem object,
+*  the column (*) can be computed with the routine glp_eval_tab_col;
+*  otherwise it can be computed with the routine glp_transform_col. */
+
+int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps)
+{     int k, m, n, piv, t, type, stat;
+      double alfa, big, beta, lb, ub, temp, teta;
+      if (glp_get_prim_stat(P) != GLP_FEAS)
+         xerror("glp_prim_rtest: basic solution is not primal feasible "
+            "\n");
+      if (!(dir == +1 || dir == -1))
+         xerror("glp_prim_rtest: dir = %d; invalid parameter\n", dir);
+      if (!(0.0 < eps && eps < 1.0))
+         xerror("glp_prim_rtest: eps = %g; invalid parameter\n", eps);
+      m = glp_get_num_rows(P);
+      n = glp_get_num_cols(P);
+      /* initial settings */
+      piv = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through the entries of the specified column */
+      for (t = 1; t <= len; t++)
+      {  /* get the ordinal number of basic variable */
+         k = ind[t];
+         if (!(1 <= k && k <= m+n))
+            xerror("glp_prim_rtest: ind[%d] = %d; variable number out o"
+               "f range\n", t, k);
+         /* determine type, bounds, status and primal value of basic
+            variable xB[i] = x[k] in the current basic solution */
+         if (k <= m)
+         {  type = glp_get_row_type(P, k);
+            lb = glp_get_row_lb(P, k);
+            ub = glp_get_row_ub(P, k);
+            stat = glp_get_row_stat(P, k);
+            beta = glp_get_row_prim(P, k);
+         }
+         else
+         {  type = glp_get_col_type(P, k-m);
+            lb = glp_get_col_lb(P, k-m);
+            ub = glp_get_col_ub(P, k-m);
+            stat = glp_get_col_stat(P, k-m);
+            beta = glp_get_col_prim(P, k-m);
+         }
+         if (stat != GLP_BS)
+            xerror("glp_prim_rtest: ind[%d] = %d; non-basic variable no"
+               "t allowed\n", t, k);
+         /* determine influence coefficient at basic variable xB[i]
+            in the explicitly specified column and turn to the case of
+            increasing the variable x in order to simplify the program
+            logic */
+         alfa = (dir > 0 ? + val[t] : - val[t]);
+         /* analyze main cases */
+         if (type == GLP_FR)
+         {  /* xB[i] is free variable */
+            continue;
+         }
+         else if (type == GLP_LO)
+lo:      {  /* xB[i] has an lower bound */
+            if (alfa > - eps) continue;
+            temp = (lb - beta) / alfa;
+         }
+         else if (type == GLP_UP)
+up:      {  /* xB[i] has an upper bound */
+            if (alfa < + eps) continue;
+            temp = (ub - beta) / alfa;
+         }
+         else if (type == GLP_DB)
+         {  /* xB[i] has both lower and upper bounds */
+            if (alfa < 0.0) goto lo; else goto up;
+         }
+         else if (type == GLP_FX)
+         {  /* xB[i] is fixed variable */
+            if (- eps < alfa && alfa < + eps) continue;
+            temp = 0.0;
+         }
+         else
+            xassert(type != type);
+         /* if the value of the variable xB[i] violates its lower or
+            upper bound (slightly, because the current basis is assumed
+            to be primal feasible), temp is negative; we can think this
+            happens due to round-off errors and the value is exactly on
+            the bound; this allows replacing temp by zero */
+         if (temp < 0.0) temp = 0.0;
+         /* apply the minimal ratio test */
+         if (teta > temp || teta == temp && big < fabs(alfa))
+            piv = t, teta = temp, big = fabs(alfa);
+      }
+      /* return index of the pivot element chosen */
+      return piv;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_dual_rtest - perform dual ratio test
+*
+*  SYNOPSIS
+*
+*  int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+*     const double val[], int dir, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine glp_dual_rtest performs the dual ratio test using an
+*  explicitly specified row of the simplex table.
+*
+*  The current basic solution associated with the LP problem object
+*  must be dual feasible.
+*
+*  The explicitly specified row of the simplex table is a linear form
+*  that shows how some basic variable x (which is not necessarily
+*  presented in the problem object) depends on non-basic variables xN:
+*
+*     x = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n]. (*)
+*
+*  The row (*) is specified on entry to the routine using the sparse
+*  format. Ordinal numbers of non-basic variables xN[j] should be placed
+*  in locations ind[1], ..., ind[len], where ordinal numbers 1 to m
+*  denote auxiliary variables, and ordinal numbers m+1 to m+n denote
+*  structural variables. The corresponding non-zero coefficients alfa[j]
+*  should be placed in locations val[1], ..., val[len]. The arrays ind
+*  and val are not changed on exit.
+*
+*  The parameter dir specifies direction in which the variable x changes
+*  on leaving the basis: +1 means that x goes to its lower bound, and -1
+*  means that x goes to its upper bound.
+*
+*  The parameter eps is an absolute tolerance (small positive number)
+*  used by the routine to skip small alfa[j] of the row (*).
+*
+*  The routine determines which non-basic variable (among specified in
+*  ind[1], ..., ind[len]) should enter the basis in order to keep dual
+*  feasibility.
+*
+*  RETURNS
+*
+*  The routine glp_dual_rtest returns the index piv in the arrays ind
+*  and val corresponding to the pivot element chosen, 1 <= piv <= len.
+*  If the adjacent basic solution is dual unbounded and therefore the
+*  choice cannot be made, the routine returns zero.
+*
+*  COMMENTS
+*
+*  If the basic variable x is presented in the LP problem object, the
+*  row (*) can be computed with the routine glp_eval_tab_row; otherwise
+*  it can be computed with the routine glp_transform_row. */
+
+int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps)
+{     int k, m, n, piv, t, stat;
+      double alfa, big, cost, obj, temp, teta;
+      if (glp_get_dual_stat(P) != GLP_FEAS)
+         xerror("glp_dual_rtest: basic solution is not dual feasible\n")
+            ;
+      if (!(dir == +1 || dir == -1))
+         xerror("glp_dual_rtest: dir = %d; invalid parameter\n", dir);
+      if (!(0.0 < eps && eps < 1.0))
+         xerror("glp_dual_rtest: eps = %g; invalid parameter\n", eps);
+      m = glp_get_num_rows(P);
+      n = glp_get_num_cols(P);
+      /* take into account optimization direction */
+      obj = (glp_get_obj_dir(P) == GLP_MIN ? +1.0 : -1.0);
+      /* initial settings */
+      piv = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through the entries of the specified row */
+      for (t = 1; t <= len; t++)
+      {  /* get ordinal number of non-basic variable */
+         k = ind[t];
+         if (!(1 <= k && k <= m+n))
+            xerror("glp_dual_rtest: ind[%d] = %d; variable number out o"
+               "f range\n", t, k);
+         /* determine status and reduced cost of non-basic variable
+            x[k] = xN[j] in the current basic solution */
+         if (k <= m)
+         {  stat = glp_get_row_stat(P, k);
+            cost = glp_get_row_dual(P, k);
+         }
+         else
+         {  stat = glp_get_col_stat(P, k-m);
+            cost = glp_get_col_dual(P, k-m);
+         }
+         if (stat == GLP_BS)
+            xerror("glp_dual_rtest: ind[%d] = %d; basic variable not al"
+               "lowed\n", t, k);
+         /* determine influence coefficient at non-basic variable xN[j]
+            in the explicitly specified row and turn to the case of
+            increasing the variable x in order to simplify the program
+            logic */
+         alfa = (dir > 0 ? + val[t] : - val[t]);
+         /* analyze main cases */
+         if (stat == GLP_NL)
+         {  /* xN[j] is on its lower bound */
+            if (alfa < + eps) continue;
+            temp = (obj * cost) / alfa;
+         }
+         else if (stat == GLP_NU)
+         {  /* xN[j] is on its upper bound */
+            if (alfa > - eps) continue;
+            temp = (obj * cost) / alfa;
+         }
+         else if (stat == GLP_NF)
+         {  /* xN[j] is non-basic free variable */
+            if (- eps < alfa && alfa < + eps) continue;
+            temp = 0.0;
+         }
+         else if (stat == GLP_NS)
+         {  /* xN[j] is non-basic fixed variable */
+            continue;
+         }
+         else
+            xassert(stat != stat);
+         /* if the reduced cost of the variable xN[j] violates its zero
+            bound (slightly, because the current basis is assumed to be
+            dual feasible), temp is negative; we can think this happens
+            due to round-off errors and the reduced cost is exact zero;
+            this allows replacing temp by zero */
+         if (temp < 0.0) temp = 0.0;
+         /* apply the minimal ratio test */
+         if (teta > temp || teta == temp && big < fabs(alfa))
+            piv = t, teta = temp, big = fabs(alfa);
+      }
+      /* return index of the pivot element chosen */
+      return piv;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_analyze_row - simulate one iteration of dual simplex method
+*
+*  SYNOPSIS
+*
+*  int glp_analyze_row(glp_prob *P, int len, const int ind[],
+*     const double val[], int type, double rhs, double eps, int *piv,
+*     double *x, double *dx, double *y, double *dy, double *dz);
+*
+*  DESCRIPTION
+*
+*  Let the current basis be optimal or dual feasible, and there be
+*  specified a row (constraint), which is violated by the current basic
+*  solution. The routine glp_analyze_row simulates one iteration of the
+*  dual simplex method to determine some information on the adjacent
+*  basis (see below), where the specified row becomes active constraint
+*  (i.e. its auxiliary variable becomes non-basic).
+*
+*  The current basic solution associated with the problem object passed
+*  to the routine must be dual feasible, and its primal components must
+*  be defined.
+*
+*  The row to be analyzed must be previously transformed either with
+*  the routine glp_eval_tab_row (if the row is in the problem object)
+*  or with the routine glp_transform_row (if the row is external, i.e.
+*  not in the problem object). This is needed to express the row only
+*  through (auxiliary and structural) variables, which are non-basic in
+*  the current basis:
+*
+*     y = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n],
+*
+*  where y is an auxiliary variable of the row, alfa[j] is an influence
+*  coefficient, xN[j] is a non-basic variable.
+*
+*  The row is passed to the routine in sparse format. Ordinal numbers
+*  of non-basic variables are stored in locations ind[1], ..., ind[len],
+*  where numbers 1 to m denote auxiliary variables while numbers m+1 to
+*  m+n denote structural variables. Corresponding non-zero coefficients
+*  alfa[j] are stored in locations val[1], ..., val[len]. The arrays
+*  ind and val are ot changed on exit.
+*
+*  The parameters type and rhs specify the row type and its right-hand
+*  side as follows:
+*
+*     type = GLP_LO: y = sum alfa[j] * xN[j] >= rhs
+*
+*     type = GLP_UP: y = sum alfa[j] * xN[j] <= rhs
+*
+*  The parameter eps is an absolute tolerance (small positive number)
+*  used by the routine to skip small coefficients alfa[j] on performing
+*  the dual ratio test.
+*
+*  If the operation was successful, the routine stores the following
+*  information to corresponding location (if some parameter is NULL,
+*  its value is not stored):
+*
+*  piv   index in the array ind and val, 1 <= piv <= len, determining
+*        the non-basic variable, which would enter the adjacent basis;
+*
+*  x     value of the non-basic variable in the current basis;
+*
+*  dx    difference between values of the non-basic variable in the
+*        adjacent and current bases, dx = x.new - x.old;
+*
+*  y     value of the row (i.e. of its auxiliary variable) in the
+*        current basis;
+*
+*  dy    difference between values of the row in the adjacent and
+*        current bases, dy = y.new - y.old;
+*
+*  dz    difference between values of the objective function in the
+*        adjacent and current bases, dz = z.new - z.old. Note that in
+*        case of minimization dz >= 0, and in case of maximization
+*        dz <= 0, i.e. in the adjacent basis the objective function
+*        always gets worse (degrades). */
+
+int _glp_analyze_row(glp_prob *P, int len, const int ind[],
+      const double val[], int type, double rhs, double eps, int *_piv,
+      double *_x, double *_dx, double *_y, double *_dy, double *_dz)
+{     int t, k, dir, piv, ret = 0;
+      double x, dx, y, dy, dz;
+      if (P->pbs_stat == GLP_UNDEF)
+         xerror("glp_analyze_row: primal basic solution components are "
+            "undefined\n");
+      if (P->dbs_stat != GLP_FEAS)
+         xerror("glp_analyze_row: basic solution is not dual feasible\n"
+            );
+      /* compute the row value y = sum alfa[j] * xN[j] in the current
+         basis */
+      if (!(0 <= len && len <= P->n))
+         xerror("glp_analyze_row: len = %d; invalid row length\n", len);
+      y = 0.0;
+      for (t = 1; t <= len; t++)
+      {  /* determine value of x[k] = xN[j] in the current basis */
+         k = ind[t];
+         if (!(1 <= k && k <= P->m+P->n))
+            xerror("glp_analyze_row: ind[%d] = %d; row/column index out"
+               " of range\n", t, k);
+         if (k <= P->m)
+         {  /* x[k] is auxiliary variable */
+            if (P->row[k]->stat == GLP_BS)
+               xerror("glp_analyze_row: ind[%d] = %d; basic auxiliary v"
+                  "ariable is not allowed\n", t, k);
+            x = P->row[k]->prim;
+         }
+         else
+         {  /* x[k] is structural variable */
+            if (P->col[k-P->m]->stat == GLP_BS)
+               xerror("glp_analyze_row: ind[%d] = %d; basic structural "
+                  "variable is not allowed\n", t, k);
+            x = P->col[k-P->m]->prim;
+         }
+         y += val[t] * x;
+      }
+      /* check if the row is primal infeasible in the current basis,
+         i.e. the constraint is violated at the current point */
+      if (type == GLP_LO)
+      {  if (y >= rhs)
+         {  /* the constraint is not violated */
+            ret = 1;
+            goto done;
+         }
+         /* in the adjacent basis y goes to its lower bound */
+         dir = +1;
+      }
+      else if (type == GLP_UP)
+      {  if (y <= rhs)
+         {  /* the constraint is not violated */
+            ret = 1;
+            goto done;
+         }
+         /* in the adjacent basis y goes to its upper bound */
+         dir = -1;
+      }
+      else
+         xerror("glp_analyze_row: type = %d; invalid parameter\n",
+            type);
+      /* compute dy = y.new - y.old */
+      dy = rhs - y;
+      /* perform dual ratio test to determine which non-basic variable
+         should enter the adjacent basis to keep it dual feasible */
+      piv = glp_dual_rtest(P, len, ind, val, dir, eps);
+      if (piv == 0)
+      {  /* no dual feasible adjacent basis exists */
+         ret = 2;
+         goto done;
+      }
+      /* non-basic variable x[k] = xN[j] should enter the basis */
+      k = ind[piv];
+      xassert(1 <= k && k <= P->m+P->n);
+      /* determine its value in the current basis */
+      if (k <= P->m)
+         x = P->row[k]->prim;
+      else
+         x = P->col[k-P->m]->prim;
+      /* compute dx = x.new - x.old = dy / alfa[j] */
+      xassert(val[piv] != 0.0);
+      dx = dy / val[piv];
+      /* compute dz = z.new - z.old = d[j] * dx, where d[j] is reduced
+         cost of xN[j] in the current basis */
+      if (k <= P->m)
+         dz = P->row[k]->dual * dx;
+      else
+         dz = P->col[k-P->m]->dual * dx;
+      /* store the analysis results */
+      if (_piv != NULL) *_piv = piv;
+      if (_x   != NULL) *_x   = x;
+      if (_dx  != NULL) *_dx  = dx;
+      if (_y   != NULL) *_y   = y;
+      if (_dy  != NULL) *_dy  = dy;
+      if (_dz  != NULL) *_dz  = dz;
+done: return ret;
+}
+
+#if 0
+int main(void)
+{     /* example program for the routine glp_analyze_row */
+      glp_prob *P;
+      glp_smcp parm;
+      int i, k, len, piv, ret, ind[1+100];
+      double rhs, x, dx, y, dy, dz, val[1+100];
+      P = glp_create_prob();
+      /* read plan.mps (see glpk/examples) */
+      ret = glp_read_mps(P, GLP_MPS_DECK, NULL, "plan.mps");
+      glp_assert(ret == 0);
+      /* and solve it to optimality */
+      ret = glp_simplex(P, NULL);
+      glp_assert(ret == 0);
+      glp_assert(glp_get_status(P) == GLP_OPT);
+      /* the optimal objective value is 296.217 */
+      /* we would like to know what happens if we would add a new row
+         (constraint) to plan.mps:
+         .01 * bin1 + .01 * bin2 + .02 * bin4 + .02 * bin5 <= 12 */
+      /* first, we specify this new row */
+      glp_create_index(P);
+      len = 0;
+      ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
+      ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
+      rhs = 12;
+      /* then we can compute value of the row (i.e. of its auxiliary
+         variable) in the current basis to see if the constraint is
+         violated */
+      y = 0.0;
+      for (k = 1; k <= len; k++)
+         y += val[k] * glp_get_col_prim(P, ind[k]);
+      glp_printf("y = %g\n", y);
+      /* this prints y = 15.1372, so the constraint is violated, since
+         we require that y <= rhs = 12 */
+      /* now we transform the row to express it only through non-basic
+         (auxiliary and artificial) variables */
+      len = glp_transform_row(P, len, ind, val);
+      /* finally, we simulate one step of the dual simplex method to
+         obtain necessary information for the adjacent basis */
+      ret = _glp_analyze_row(P, len, ind, val, GLP_UP, rhs, 1e-9, &piv,
+         &x, &dx, &y, &dy, &dz);
+      glp_assert(ret == 0);
+      glp_printf("k = %d, x = %g; dx = %g; y = %g; dy = %g; dz = %g\n",
+         ind[piv], x, dx, y, dy, dz);
+      /* this prints dz = 5.64418 and means that in the adjacent basis
+         the objective function would be 296.217 + 5.64418 = 301.861 */
+      /* now we actually include the row into the problem object; note
+         that the arrays ind and val are clobbered, so we need to build
+         them once again */
+      len = 0;
+      ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01;
+      ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02;
+      ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02;
+      rhs = 12;
+      i = glp_add_rows(P, 1);
+      glp_set_row_bnds(P, i, GLP_UP, 0, rhs);
+      glp_set_mat_row(P, i, len, ind, val);
+      /* and perform one dual simplex iteration */
+      glp_init_smcp(&parm);
+      parm.meth = GLP_DUAL;
+      parm.it_lim = 1;
+      glp_simplex(P, &parm);
+      /* the current objective value is 301.861 */
+      return 0;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  glp_analyze_bound - analyze active bound of non-basic variable
+*
+*  SYNOPSIS
+*
+*  void glp_analyze_bound(glp_prob *P, int k, double *limit1, int *var1,
+*     double *limit2, int *var2);
+*
+*  DESCRIPTION
+*
+*  The routine glp_analyze_bound analyzes the effect of varying the
+*  active bound of specified non-basic variable.
+*
+*  The non-basic variable is specified by the parameter k, where
+*  1 <= k <= m means auxiliary variable of corresponding row while
+*  m+1 <= k <= m+n means structural variable (column).
+*
+*  Note that the current basic solution must be optimal, and the basis
+*  factorization must exist.
+*
+*  Results of the analysis have the following meaning.
+*
+*  value1 is the minimal value of the active bound, at which the basis
+*  still remains primal feasible and thus optimal. -DBL_MAX means that
+*  the active bound has no lower limit.
+*
+*  var1 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) basic variable, which reaches its bound first and thereby
+*  limits further decreasing the active bound being analyzed.
+*  if value1 = -DBL_MAX, var1 is set to 0.
+*
+*  value2 is the maximal value of the active bound, at which the basis
+*  still remains primal feasible and thus optimal. +DBL_MAX means that
+*  the active bound has no upper limit.
+*
+*  var2 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) basic variable, which reaches its bound first and thereby
+*  limits further increasing the active bound being analyzed.
+*  if value2 = +DBL_MAX, var2 is set to 0. */
+
+void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
+      double *value2, int *var2)
+{     GLPROW *row;
+      GLPCOL *col;
+      int m, n, stat, kase, p, len, piv, *ind;
+      double x, new_x, ll, uu, xx, delta, *val;
+      /* sanity checks */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_analyze_bound: P = %p; invalid problem object\n",
+            P);
+      m = P->m, n = P->n;
+      if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+         xerror("glp_analyze_bound: optimal basic solution required\n");
+      if (!(m == 0 || P->valid))
+         xerror("glp_analyze_bound: basis factorization required\n");
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_analyze_bound: k = %d; variable number out of rang"
+            "e\n", k);
+      /* retrieve information about the specified non-basic variable
+         x[k] whose active bound is to be analyzed */
+      if (k <= m)
+      {  row = P->row[k];
+         stat = row->stat;
+         x = row->prim;
+      }
+      else
+      {  col = P->col[k-m];
+         stat = col->stat;
+         x = col->prim;
+      }
+      if (stat == GLP_BS)
+         xerror("glp_analyze_bound: k = %d; basic variable not allowed "
+            "\n", k);
+      /* allocate working arrays */
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      /* compute column of the simplex table corresponding to the
+         non-basic variable x[k] */
+      len = glp_eval_tab_col(P, k, ind, val);
+      xassert(0 <= len && len <= m);
+      /* perform analysis */
+      for (kase = -1; kase <= +1; kase += 2)
+      {  /* kase < 0 means active bound of x[k] is decreasing;
+            kase > 0 means active bound of x[k] is increasing */
+         /* use the primal ratio test to determine some basic variable
+            x[p] which reaches its bound first */
+         piv = glp_prim_rtest(P, len, ind, val, kase, 1e-9);
+         if (piv == 0)
+         {  /* nothing limits changing the active bound of x[k] */
+            p = 0;
+            new_x = (kase < 0 ? -DBL_MAX : +DBL_MAX);
+            goto store;
+         }
+         /* basic variable x[p] limits changing the active bound of
+            x[k]; determine its value in the current basis */
+         xassert(1 <= piv && piv <= len);
+         p = ind[piv];
+         if (p <= m)
+         {  row = P->row[p];
+            ll = glp_get_row_lb(P, row->i);
+            uu = glp_get_row_ub(P, row->i);
+            stat = row->stat;
+            xx = row->prim;
+         }
+         else
+         {  col = P->col[p-m];
+            ll = glp_get_col_lb(P, col->j);
+            uu = glp_get_col_ub(P, col->j);
+            stat = col->stat;
+            xx = col->prim;
+         }
+         xassert(stat == GLP_BS);
+         /* determine delta x[p] = bound of x[p] - value of x[p] */
+         if (kase < 0 && val[piv] > 0.0 ||
+             kase > 0 && val[piv] < 0.0)
+         {  /* delta x[p] < 0, so x[p] goes toward its lower bound */
+            xassert(ll != -DBL_MAX);
+            delta = ll - xx;
+         }
+         else
+         {  /* delta x[p] > 0, so x[p] goes toward its upper bound */
+            xassert(uu != +DBL_MAX);
+            delta = uu - xx;
+         }
+         /* delta x[p] = alfa[p,k] * delta x[k], so new x[k] = x[k] +
+            delta x[k] = x[k] + delta x[p] / alfa[p,k] is the value of
+            x[k] in the adjacent basis */
+         xassert(val[piv] != 0.0);
+         new_x = x + delta / val[piv];
+store:   /* store analysis results */
+         if (kase < 0)
+         {  if (value1 != NULL) *value1 = new_x;
+            if (var1 != NULL) *var1 = p;
+         }
+         else
+         {  if (value2 != NULL) *value2 = new_x;
+            if (var2 != NULL) *var2 = p;
+         }
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_analyze_coef - analyze objective coefficient at basic variable
+*
+*  SYNOPSIS
+*
+*  void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+*     double *value1, double *coef2, int *var2, double *value2);
+*
+*  DESCRIPTION
+*
+*  The routine glp_analyze_coef analyzes the effect of varying the
+*  objective coefficient at specified basic variable.
+*
+*  The basic variable is specified by the parameter k, where
+*  1 <= k <= m means auxiliary variable of corresponding row while
+*  m+1 <= k <= m+n means structural variable (column).
+*
+*  Note that the current basic solution must be optimal, and the basis
+*  factorization must exist.
+*
+*  Results of the analysis have the following meaning.
+*
+*  coef1 is the minimal value of the objective coefficient, at which
+*  the basis still remains dual feasible and thus optimal. -DBL_MAX
+*  means that the objective coefficient has no lower limit.
+*
+*  var1 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) non-basic variable, whose reduced cost reaches its zero
+*  bound first and thereby limits further decreasing the objective
+*  coefficient being analyzed. If coef1 = -DBL_MAX, var1 is set to 0.
+*
+*  value1 is value of the basic variable being analyzed in an adjacent
+*  basis, which is defined as follows. Let the objective coefficient
+*  reaches its minimal value (coef1) and continues decreasing. Then the
+*  reduced cost of the limiting non-basic variable (var1) becomes dual
+*  infeasible and the current basis becomes non-optimal that forces the
+*  limiting non-basic variable to enter the basis replacing there some
+*  basic variable that leaves the basis to keep primal feasibility.
+*  Should note that on determining the adjacent basis current bounds
+*  of the basic variable being analyzed are ignored as if it were free
+*  (unbounded) variable, so it cannot leave the basis. It may happen
+*  that no dual feasible adjacent basis exists, in which case value1 is
+*  set to -DBL_MAX or +DBL_MAX.
+*
+*  coef2 is the maximal value of the objective coefficient, at which
+*  the basis still remains dual feasible and thus optimal. +DBL_MAX
+*  means that the objective coefficient has no upper limit.
+*
+*  var2 is the ordinal number of an auxiliary (1 to m) or structural
+*  (m+1 to n) non-basic variable, whose reduced cost reaches its zero
+*  bound first and thereby limits further increasing the objective
+*  coefficient being analyzed. If coef2 = +DBL_MAX, var2 is set to 0.
+*
+*  value2 is value of the basic variable being analyzed in an adjacent
+*  basis, which is defined exactly in the same way as value1 above with
+*  exception that now the objective coefficient is increasing. */
+
+void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+      double *value1, double *coef2, int *var2, double *value2)
+{     GLPROW *row; GLPCOL *col;
+      int m, n, type, stat, kase, p, q, dir, clen, cpiv, rlen, rpiv,
+         *cind, *rind;
+      double lb, ub, coef, x, lim_coef, new_x, d, delta, ll, uu, xx,
+         *rval, *cval;
+      /* sanity checks */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_analyze_coef: P = %p; invalid problem object\n",
+            P);
+      m = P->m, n = P->n;
+      if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS))
+         xerror("glp_analyze_coef: optimal basic solution required\n");
+      if (!(m == 0 || P->valid))
+         xerror("glp_analyze_coef: basis factorization required\n");
+      if (!(1 <= k && k <= m+n))
+         xerror("glp_analyze_coef: k = %d; variable number out of range"
+            "\n", k);
+      /* retrieve information about the specified basic variable x[k]
+         whose objective coefficient c[k] is to be analyzed */
+      if (k <= m)
+      {  row = P->row[k];
+         type = row->type;
+         lb = row->lb;
+         ub = row->ub;
+         coef = 0.0;
+         stat = row->stat;
+         x = row->prim;
+      }
+      else
+      {  col = P->col[k-m];
+         type = col->type;
+         lb = col->lb;
+         ub = col->ub;
+         coef = col->coef;
+         stat = col->stat;
+         x = col->prim;
+      }
+      if (stat != GLP_BS)
+         xerror("glp_analyze_coef: k = %d; non-basic variable not allow"
+            "ed\n", k);
+      /* allocate working arrays */
+      cind = xcalloc(1+m, sizeof(int));
+      cval = xcalloc(1+m, sizeof(double));
+      rind = xcalloc(1+n, sizeof(int));
+      rval = xcalloc(1+n, sizeof(double));
+      /* compute row of the simplex table corresponding to the basic
+         variable x[k] */
+      rlen = glp_eval_tab_row(P, k, rind, rval);
+      xassert(0 <= rlen && rlen <= n);
+      /* perform analysis */
+      for (kase = -1; kase <= +1; kase += 2)
+      {  /* kase < 0 means objective coefficient c[k] is decreasing;
+            kase > 0 means objective coefficient c[k] is increasing */
+         /* note that decreasing c[k] is equivalent to increasing dual
+            variable lambda[k] and vice versa; we need to correctly set
+            the dir flag as required by the routine glp_dual_rtest */
+         if (P->dir == GLP_MIN)
+            dir = - kase;
+         else if (P->dir == GLP_MAX)
+            dir = + kase;
+         else
+            xassert(P != P);
+         /* use the dual ratio test to determine non-basic variable
+            x[q] whose reduced cost d[q] reaches zero bound first */
+         rpiv = glp_dual_rtest(P, rlen, rind, rval, dir, 1e-9);
+         if (rpiv == 0)
+         {  /* nothing limits changing c[k] */
+            lim_coef = (kase < 0 ? -DBL_MAX : +DBL_MAX);
+            q = 0;
+            /* x[k] keeps its current value */
+            new_x = x;
+            goto store;
+         }
+         /* non-basic variable x[q] limits changing coefficient c[k];
+            determine its status and reduced cost d[k] in the current
+            basis */
+         xassert(1 <= rpiv && rpiv <= rlen);
+         q = rind[rpiv];
+         xassert(1 <= q && q <= m+n);
+         if (q <= m)
+         {  row = P->row[q];
+            stat = row->stat;
+            d = row->dual;
+         }
+         else
+         {  col = P->col[q-m];
+            stat = col->stat;
+            d = col->dual;
+         }
+         /* note that delta d[q] = new d[q] - d[q] = - d[q], because
+            new d[q] = 0; delta d[q] = alfa[k,q] * delta c[k], so
+            delta c[k] = delta d[q] / alfa[k,q] = - d[q] / alfa[k,q] */
+         xassert(rval[rpiv] != 0.0);
+         delta = - d / rval[rpiv];
+         /* compute new c[k] = c[k] + delta c[k], which is the limiting
+            value of the objective coefficient c[k] */
+         lim_coef = coef + delta;
+         /* let c[k] continue decreasing/increasing that makes d[q]
+            dual infeasible and forces x[q] to enter the basis;
+            to perform the primal ratio test we need to know in which
+            direction x[q] changes on entering the basis; we determine
+            that analyzing the sign of delta d[q] (see above), since
+            d[q] may be close to zero having wrong sign */
+         /* let, for simplicity, the problem is minimization */
+         if (kase < 0 && rval[rpiv] > 0.0 ||
+             kase > 0 && rval[rpiv] < 0.0)
+         {  /* delta d[q] < 0, so d[q] being non-negative will become
+               negative, so x[q] will increase */
+            dir = +1;
+         }
+         else
+         {  /* delta d[q] > 0, so d[q] being non-positive will become
+               positive, so x[q] will decrease */
+            dir = -1;
+         }
+         /* if the problem is maximization, correct the direction */
+         if (P->dir == GLP_MAX) dir = - dir;
+         /* check that we didn't make a silly mistake */
+         if (dir > 0)
+            xassert(stat == GLP_NL || stat == GLP_NF);
+         else
+            xassert(stat == GLP_NU || stat == GLP_NF);
+         /* compute column of the simplex table corresponding to the
+            non-basic variable x[q] */
+         clen = glp_eval_tab_col(P, q, cind, cval);
+         /* make x[k] temporarily free (unbounded) */
+         if (k <= m)
+         {  row = P->row[k];
+            row->type = GLP_FR;
+            row->lb = row->ub = 0.0;
+         }
+         else
+         {  col = P->col[k-m];
+            col->type = GLP_FR;
+            col->lb = col->ub = 0.0;
+         }
+         /* use the primal ratio test to determine some basic variable
+            which leaves the basis */
+         cpiv = glp_prim_rtest(P, clen, cind, cval, dir, 1e-9);
+         /* restore original bounds of the basic variable x[k] */
+         if (k <= m)
+         {  row = P->row[k];
+            row->type = type;
+            row->lb = lb, row->ub = ub;
+         }
+         else
+         {  col = P->col[k-m];
+            col->type = type;
+            col->lb = lb, col->ub = ub;
+         }
+         if (cpiv == 0)
+         {  /* non-basic variable x[q] can change unlimitedly */
+            if (dir < 0 && rval[rpiv] > 0.0 ||
+                dir > 0 && rval[rpiv] < 0.0)
+            {  /* delta x[k] = alfa[k,q] * delta x[q] < 0 */
+               new_x = -DBL_MAX;
+            }
+            else
+            {  /* delta x[k] = alfa[k,q] * delta x[q] > 0 */
+               new_x = +DBL_MAX;
+            }
+            goto store;
+         }
+         /* some basic variable x[p] limits changing non-basic variable
+            x[q] in the adjacent basis */
+         xassert(1 <= cpiv && cpiv <= clen);
+         p = cind[cpiv];
+         xassert(1 <= p && p <= m+n);
+         xassert(p != k);
+         if (p <= m)
+         {  row = P->row[p];
+            xassert(row->stat == GLP_BS);
+            ll = glp_get_row_lb(P, row->i);
+            uu = glp_get_row_ub(P, row->i);
+            xx = row->prim;
+         }
+         else
+         {  col = P->col[p-m];
+            xassert(col->stat == GLP_BS);
+            ll = glp_get_col_lb(P, col->j);
+            uu = glp_get_col_ub(P, col->j);
+            xx = col->prim;
+         }
+         /* determine delta x[p] = new x[p] - x[p] */
+         if (dir < 0 && cval[cpiv] > 0.0 ||
+             dir > 0 && cval[cpiv] < 0.0)
+         {  /* delta x[p] < 0, so x[p] goes toward its lower bound */
+            xassert(ll != -DBL_MAX);
+            delta = ll - xx;
+         }
+         else
+         {  /* delta x[p] > 0, so x[p] goes toward its upper bound */
+            xassert(uu != +DBL_MAX);
+            delta = uu - xx;
+         }
+         /* compute new x[k] = x[k] + alfa[k,q] * delta x[q], where
+            delta x[q] = delta x[p] / alfa[p,q] */
+         xassert(cval[cpiv] != 0.0);
+         new_x = x + (rval[rpiv] / cval[cpiv]) * delta;
+store:   /* store analysis results */
+         if (kase < 0)
+         {  if (coef1 != NULL) *coef1 = lim_coef;
+            if (var1 != NULL) *var1 = q;
+            if (value1 != NULL) *value1 = new_x;
+         }
+         else
+         {  if (coef2 != NULL) *coef2 = lim_coef;
+            if (var2 != NULL) *var2 = q;
+            if (value2 != NULL) *value2 = new_x;
+         }
+      }
+      /* free working arrays */
+      xfree(cind);
+      xfree(cval);
+      xfree(rind);
+      xfree(rval);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi13.c
===================================================================
--- deps/glpk/src/glpapi13.c	(revision 9)
+++ deps/glpk/src/glpapi13.c	(revision 9)
@@ -0,0 +1,702 @@
+/* glpapi13.c (branch-and-bound interface routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_reason - determine reason for calling the callback routine
+*
+*  SYNOPSIS
+*
+*  glp_ios_reason(glp_tree *tree);
+*
+*  RETURNS
+*
+*  The routine glp_ios_reason returns a code, which indicates why the
+*  user-defined callback routine is being called. */
+
+int glp_ios_reason(glp_tree *tree)
+{     return
+         tree->reason;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_get_prob - access the problem object
+*
+*  SYNOPSIS
+*
+*  glp_prob *glp_ios_get_prob(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_get_prob can be called from the user-defined
+*  callback routine to access the problem object, which is used by the
+*  MIP solver. It is the original problem object passed to the routine
+*  glp_intopt if the MIP presolver is not used; otherwise it is an
+*  internal problem object built by the presolver. If the current
+*  subproblem exists, LP segment of the problem object corresponds to
+*  its LP relaxation.
+*
+*  RETURNS
+*
+*  The routine glp_ios_get_prob returns a pointer to the problem object
+*  used by the MIP solver. */
+
+glp_prob *glp_ios_get_prob(glp_tree *tree)
+{     return
+         tree->mip;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_tree_size - determine size of the branch-and-bound tree
+*
+*  SYNOPSIS
+*
+*  void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
+*     int *t_cnt);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_tree_size stores the following three counts which
+*  characterize the current size of the branch-and-bound tree:
+*
+*  a_cnt is the current number of active nodes, i.e. the current size of
+*        the active list;
+*
+*  n_cnt is the current number of all (active and inactive) nodes;
+*
+*  t_cnt is the total number of nodes including those which have been
+*        already removed from the tree. This count is increased whenever
+*        a new node appears in the tree and never decreased.
+*
+*  If some of the parameters a_cnt, n_cnt, t_cnt is a null pointer, the
+*  corresponding count is not stored. */
+
+void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
+      int *t_cnt)
+{     if (a_cnt != NULL) *a_cnt = tree->a_cnt;
+      if (n_cnt != NULL) *n_cnt = tree->n_cnt;
+      if (t_cnt != NULL) *t_cnt = tree->t_cnt;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_curr_node - determine current active subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_curr_node(glp_tree *tree);
+*
+*  RETURNS
+*
+*  The routine glp_ios_curr_node returns the reference number of the
+*  current active subproblem. However, if the current subproblem does
+*  not exist, the routine returns zero. */
+
+int glp_ios_curr_node(glp_tree *tree)
+{     IOSNPD *node;
+      /* obtain pointer to the current subproblem */
+      node = tree->curr;
+      /* return its reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_next_node - determine next active subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_next_node(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  If the parameter p is zero, the routine glp_ios_next_node returns
+*  the reference number of the first active subproblem. However, if the
+*  tree is empty, zero is returned.
+*
+*  If the parameter p is not zero, it must specify the reference number
+*  of some active subproblem, in which case the routine returns the
+*  reference number of the next active subproblem. However, if there is
+*  no next active subproblem in the list, zero is returned.
+*
+*  All subproblems in the active list are ordered chronologically, i.e.
+*  subproblem A precedes subproblem B if A was created before B. */
+
+int glp_ios_next_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      if (p == 0)
+      {  /* obtain pointer to the first active subproblem */
+         node = tree->head;
+      }
+      else
+      {  /* obtain pointer to the specified subproblem */
+         if (!(1 <= p && p <= tree->nslots))
+err:        xerror("glp_ios_next_node: p = %d; invalid subproblem refer"
+               "ence number\n", p);
+         node = tree->slot[p].node;
+         if (node == NULL) goto err;
+         /* the specified subproblem must be active */
+         if (node->count != 0)
+            xerror("glp_ios_next_node: p = %d; subproblem not in the ac"
+               "tive list\n", p);
+         /* obtain pointer to the next active subproblem */
+         node = node->next;
+      }
+      /* return the reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_prev_node - determine previous active subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_prev_node(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  If the parameter p is zero, the routine glp_ios_prev_node returns
+*  the reference number of the last active subproblem. However, if the
+*  tree is empty, zero is returned.
+*
+*  If the parameter p is not zero, it must specify the reference number
+*  of some active subproblem, in which case the routine returns the
+*  reference number of the previous active subproblem. However, if there
+*  is no previous active subproblem in the list, zero is returned.
+*
+*  All subproblems in the active list are ordered chronologically, i.e.
+*  subproblem A precedes subproblem B if A was created before B. */
+
+int glp_ios_prev_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      if (p == 0)
+      {  /* obtain pointer to the last active subproblem */
+         node = tree->tail;
+      }
+      else
+      {  /* obtain pointer to the specified subproblem */
+         if (!(1 <= p && p <= tree->nslots))
+err:        xerror("glp_ios_prev_node: p = %d; invalid subproblem refer"
+               "ence number\n", p);
+         node = tree->slot[p].node;
+         if (node == NULL) goto err;
+         /* the specified subproblem must be active */
+         if (node->count != 0)
+            xerror("glp_ios_prev_node: p = %d; subproblem not in the ac"
+               "tive list\n", p);
+         /* obtain pointer to the previous active subproblem */
+         node = node->prev;
+      }
+      /* return the reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_up_node - determine parent subproblem
+*
+*  SYNOPSIS
+*
+*  int glp_ios_up_node(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  The parameter p must specify the reference number of some (active or
+*  inactive) subproblem, in which case the routine iet_get_up_node
+*  returns the reference number of its parent subproblem. However, if
+*  the specified subproblem is the root of the tree and, therefore, has
+*  no parent, the routine returns zero. */
+
+int glp_ios_up_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_up_node: p = %d; invalid subproblem reference "
+            "number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* obtain pointer to the parent subproblem */
+      node = node->up;
+      /* return the reference number */
+      return node == NULL ? 0 : node->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_node_level - determine subproblem level
+*
+*  SYNOPSIS
+*
+*  int glp_ios_node_level(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  The routine glp_ios_node_level returns the level of the subproblem,
+*  whose reference number is p, in the branch-and-bound tree. (The root
+*  subproblem has level 0, and the level of any other subproblem is the
+*  level of its parent plus one.) */
+
+int glp_ios_node_level(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
+            "ce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* return the node level */
+      return node->level;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_node_bound - determine subproblem local bound
+*
+*  SYNOPSIS
+*
+*  double glp_ios_node_bound(glp_tree *tree, int p);
+*
+*  RETURNS
+*
+*  The routine glp_ios_node_bound returns the local bound for (active or
+*  inactive) subproblem, whose reference number is p.
+*
+*  COMMENTS
+*
+*  The local bound for subproblem p is an lower (minimization) or upper
+*  (maximization) bound for integer optimal solution to this subproblem
+*  (not to the original problem). This bound is local in the sense that
+*  only subproblems in the subtree rooted at node p cannot have better
+*  integer feasible solutions.
+*
+*  On creating a subproblem (due to the branching step) its local bound
+*  is inherited from its parent and then may get only stronger (never
+*  weaker). For the root subproblem its local bound is initially set to
+*  -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved
+*  as the root LP relaxation has been solved.
+*
+*  Note that the local bound is not necessarily the optimal objective
+*  value to corresponding LP relaxation; it may be stronger. */
+
+double glp_ios_node_bound(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_node_bound: p = %d; invalid subproblem referen"
+            "ce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* return the node local bound */
+      return node->bound;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_best_node - find active subproblem with best local bound
+*
+*  SYNOPSIS
+*
+*  int glp_ios_best_node(glp_tree *tree);
+*
+*  RETURNS
+*
+*  The routine glp_ios_best_node returns the reference number of the
+*  active subproblem, whose local bound is best (i.e. smallest in case
+*  of minimization or largest in case of maximization). However, if the
+*  tree is empty, the routine returns zero.
+*
+*  COMMENTS
+*
+*  The best local bound is an lower (minimization) or upper
+*  (maximization) bound for integer optimal solution to the original
+*  MIP problem. */
+
+int glp_ios_best_node(glp_tree *tree)
+{     return
+         ios_best_node(tree);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_mip_gap - compute relative MIP gap
+*
+*  SYNOPSIS
+*
+*  double glp_ios_mip_gap(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_mip_gap computes the relative MIP gap with the
+*  following formula:
+*
+*     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
+*
+*  where best_mip is the best integer feasible solution found so far,
+*  best_bnd is the best (global) bound. If no integer feasible solution
+*  has been found yet, gap is set to DBL_MAX.
+*
+*  RETURNS
+*
+*  The routine glp_ios_mip_gap returns the relative MIP gap. */
+
+double glp_ios_mip_gap(glp_tree *tree)
+{     return
+         ios_relative_gap(tree);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_node_data - access subproblem application-specific data
+*
+*  SYNOPSIS
+*
+*  void *glp_ios_node_data(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_node_data allows the application accessing a
+*  memory block allocated for the subproblem (which may be active or
+*  inactive), whose reference number is p.
+*
+*  The size of the block is defined by the control parameter cb_size
+*  passed to the routine glp_intopt. The block is initialized by binary
+*  zeros on creating corresponding subproblem, and its contents is kept
+*  until the subproblem will be removed from the tree.
+*
+*  The application may use these memory blocks to store specific data
+*  for each subproblem.
+*
+*  RETURNS
+*
+*  The routine glp_ios_node_data returns a pointer to the memory block
+*  for the specified subproblem. Note that if cb_size = 0, the routine
+*  returns a null pointer. */
+
+void *glp_ios_node_data(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
+            "ce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* return pointer to the application-specific data */
+      return node->data;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_row_attr - retrieve additional row attributes
+*
+*  SYNOPSIS
+*
+*  void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_row_attr retrieves additional attributes of row
+*  i and stores them in the structure glp_attr. */
+
+void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr)
+{     GLPROW *row;
+      if (!(1 <= i && i <= tree->mip->m))
+         xerror("glp_ios_row_attr: i = %d; row number out of range\n",
+            i);
+      row = tree->mip->row[i];
+      attr->level = row->level;
+      attr->origin = row->origin;
+      attr->klass = row->klass;
+      return;
+}
+
+/**********************************************************************/
+
+int glp_ios_pool_size(glp_tree *tree)
+{     /* determine current size of the cut pool */
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_pool_size: operation not allowed\n");
+      xassert(tree->local != NULL);
+      return tree->local->size;
+}
+
+/**********************************************************************/
+
+int glp_ios_add_row(glp_tree *tree,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs)
+{     /* add row (constraint) to the cut pool */
+      int num;
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_add_row: operation not allowed\n");
+      xassert(tree->local != NULL);
+      num = ios_add_row(tree, tree->local, name, klass, flags, len,
+         ind, val, type, rhs);
+      return num;
+}
+
+/**********************************************************************/
+
+void glp_ios_del_row(glp_tree *tree, int i)
+{     /* remove row (constraint) from the cut pool */
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_del_row: operation not allowed\n");
+      ios_del_row(tree, tree->local, i);
+      return;
+}
+
+/**********************************************************************/
+
+void glp_ios_clear_pool(glp_tree *tree)
+{     /* remove all rows (constraints) from the cut pool */
+      if (tree->reason != GLP_ICUTGEN)
+         xerror("glp_ios_clear_pool: operation not allowed\n");
+      ios_clear_pool(tree, tree->local);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_can_branch - check if can branch upon specified variable
+*
+*  SYNOPSIS
+*
+*  int glp_ios_can_branch(glp_tree *tree, int j);
+*
+*  RETURNS
+*
+*  If j-th variable (column) can be used to branch upon, the routine
+*  glp_ios_can_branch returns non-zero, otherwise zero. */
+
+int glp_ios_can_branch(glp_tree *tree, int j)
+{     if (!(1 <= j && j <= tree->mip->n))
+         xerror("glp_ios_can_branch: j = %d; column number out of range"
+            "\n", j);
+      return tree->non_int[j];
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_branch_upon - choose variable to branch upon
+*
+*  SYNOPSIS
+*
+*  void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_branch_upon can be called from the user-defined
+*  callback routine in response to the reason GLP_IBRANCH to choose a
+*  branching variable, whose ordinal number is j. Should note that only
+*  variables, for which the routine glp_ios_can_branch returns non-zero,
+*  can be used to branch upon.
+*
+*  The parameter sel is a flag that indicates which branch (subproblem)
+*  should be selected next to continue the search:
+*
+*  GLP_DN_BRNCH - select down-branch;
+*  GLP_UP_BRNCH - select up-branch;
+*  GLP_NO_BRNCH - use general selection technique. */
+
+void glp_ios_branch_upon(glp_tree *tree, int j, int sel)
+{     if (!(1 <= j && j <= tree->mip->n))
+         xerror("glp_ios_branch_upon: j = %d; column number out of rang"
+            "e\n", j);
+      if (!(sel == GLP_DN_BRNCH || sel == GLP_UP_BRNCH ||
+            sel == GLP_NO_BRNCH))
+         xerror("glp_ios_branch_upon: sel = %d: invalid branch selectio"
+            "n flag\n", sel);
+      if (!(tree->non_int[j]))
+         xerror("glp_ios_branch_upon: j = %d; variable cannot be used t"
+            "o branch upon\n", j);
+      if (tree->br_var != 0)
+         xerror("glp_ios_branch_upon: branching variable already chosen"
+            "\n");
+      tree->br_var = j;
+      tree->br_sel = sel;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_select_node - select subproblem to continue the search
+*
+*  SYNOPSIS
+*
+*  void glp_ios_select_node(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_select_node can be called from the user-defined
+*  callback routine in response to the reason GLP_ISELECT to select an
+*  active subproblem, whose reference number is p. The search will be
+*  continued from the subproblem selected. */
+
+void glp_ios_select_node(glp_tree *tree, int p)
+{     IOSNPD *node;
+      /* obtain pointer to the specified subproblem */
+      if (!(1 <= p && p <= tree->nslots))
+err:     xerror("glp_ios_select_node: p = %d; invalid subproblem refere"
+            "nce number\n", p);
+      node = tree->slot[p].node;
+      if (node == NULL) goto err;
+      /* the specified subproblem must be active */
+      if (node->count != 0)
+         xerror("glp_ios_select_node: p = %d; subproblem not in the act"
+            "ive list\n", p);
+      /* no subproblem must be selected yet */
+      if (tree->next_p != 0)
+         xerror("glp_ios_select_node: subproblem already selected\n");
+      /* select the specified subproblem to continue the search */
+      tree->next_p = p;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_heur_sol - provide solution found by heuristic
+*
+*  SYNOPSIS
+*
+*  int glp_ios_heur_sol(glp_tree *tree, const double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_heur_sol can be called from the user-defined
+*  callback routine in response to the reason GLP_IHEUR to provide an
+*  integer feasible solution found by a primal heuristic.
+*
+*  Primal values of *all* variables (columns) found by the heuristic
+*  should be placed in locations x[1], ..., x[n], where n is the number
+*  of columns in the original problem object. Note that the routine
+*  glp_ios_heur_sol *does not* check primal feasibility of the solution
+*  provided.
+*
+*  Using the solution passed in the array x the routine computes value
+*  of the objective function. If the objective value is better than the
+*  best known integer feasible solution, the routine computes values of
+*  auxiliary variables (rows) and stores all solution components in the
+*  problem object.
+*
+*  RETURNS
+*
+*  If the provided solution is accepted, the routine glp_ios_heur_sol
+*  returns zero. Otherwise, if the provided solution is rejected, the
+*  routine returns non-zero. */
+
+int glp_ios_heur_sol(glp_tree *tree, const double x[])
+{     glp_prob *mip = tree->mip;
+      int m = tree->orig_m;
+      int n = tree->n;
+      int i, j;
+      double obj;
+      xassert(mip->m >= m);
+      xassert(mip->n == n);
+      /* check values of integer variables and compute value of the
+         objective function */
+      obj = mip->c0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         if (col->kind == GLP_IV)
+         {  /* provided value must be integral */
+            if (x[j] != floor(x[j])) return 1;
+         }
+         obj += col->coef * x[j];
+      }
+      /* check if the provided solution is better than the best known
+         integer feasible solution */
+      if (mip->mip_stat == GLP_FEAS)
+      {  switch (mip->dir)
+         {  case GLP_MIN:
+               if (obj >= tree->mip->mip_obj) return 1;
+               break;
+            case GLP_MAX:
+               if (obj <= tree->mip->mip_obj) return 1;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      /* it is better; store it in the problem object */
+      if (tree->parm->msg_lev >= GLP_MSG_ON)
+         xprintf("Solution found by heuristic: %.12g\n", obj);
+      mip->mip_stat = GLP_FEAS;
+      mip->mip_obj = obj;
+      for (j = 1; j <= n; j++)
+         mip->col[j]->mipx = x[j];
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = mip->row[i];
+         GLPAIJ *aij;
+         row->mipx = 0.0;
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            row->mipx += aij->val * aij->col->mipx;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_ios_terminate - terminate the solution process.
+*
+*  SYNOPSIS
+*
+*  void glp_ios_terminate(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine glp_ios_terminate sets a flag indicating that the MIP
+*  solver should prematurely terminate the search. */
+
+void glp_ios_terminate(glp_tree *tree)
+{     if (tree->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("The search is prematurely terminated due to applicati"
+            "on request\n");
+      tree->stop = 1;
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi14.c
===================================================================
--- deps/glpk/src/glpapi14.c	(revision 9)
+++ deps/glpk/src/glpapi14.c	(revision 9)
@@ -0,0 +1,274 @@
+/* glpapi14.c (processing models in GNU MathProg language) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define GLP_TRAN_DEFINED
+typedef struct MPL glp_tran;
+
+#include "glpmpl.h"
+#include "glpapi.h"
+
+glp_tran *glp_mpl_alloc_wksp(void)
+{     /* allocate the MathProg translator workspace */
+      glp_tran *tran;
+      tran = mpl_initialize();
+      return tran;
+}
+
+#if 1 /* 08/XII-2009 */
+void _glp_mpl_init_rand(glp_tran *tran, int seed)
+{     if (tran->phase != 0)
+         xerror("glp_mpl_init_rand: invalid call sequence\n");
+      rng_init_rand(tran->rand, seed);
+      return;
+}
+#endif
+
+int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip)
+{     /* read and translate model section */
+      int ret;
+      if (tran->phase != 0)
+         xerror("glp_mpl_read_model: invalid call sequence\n");
+      ret = mpl_read_model(tran, (char *)fname, skip);
+      if (ret == 1 || ret == 2)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+      else
+         xassert(ret != ret);
+      return ret;
+}
+
+int glp_mpl_read_data(glp_tran *tran, const char *fname)
+{     /* read and translate data section */
+      int ret;
+      if (!(tran->phase == 1 || tran->phase == 2))
+         xerror("glp_mpl_read_data: invalid call sequence\n");
+      ret = mpl_read_data(tran, (char *)fname);
+      if (ret == 2)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+      else
+         xassert(ret != ret);
+      return ret;
+}
+
+int glp_mpl_generate(glp_tran *tran, const char *fname)
+{     /* generate the model */
+      int ret;
+      if (!(tran->phase == 1 || tran->phase == 2))
+         xerror("glp_mpl_generate: invalid call sequence\n");
+      ret = mpl_generate(tran, (char *)fname);
+      if (ret == 3)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+      return ret;
+}
+
+void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob)
+{     /* build LP/MIP problem instance from the model */
+      int m, n, i, j, t, kind, type, len, *ind;
+      double lb, ub, *val;
+      if (tran->phase != 3)
+         xerror("glp_mpl_build_prob: invalid call sequence\n");
+      /* erase the problem object */
+      glp_erase_prob(prob);
+      /* set problem name */
+      glp_set_prob_name(prob, mpl_get_prob_name(tran));
+      /* build rows (constraints) */
+      m = mpl_get_num_rows(tran);
+      if (m > 0)
+         glp_add_rows(prob, m);
+      for (i = 1; i <= m; i++)
+      {  /* set row name */
+         glp_set_row_name(prob, i, mpl_get_row_name(tran, i));
+         /* set row bounds */
+         type = mpl_get_row_bnds(tran, i, &lb, &ub);
+         switch (type)
+         {  case MPL_FR: type = GLP_FR; break;
+            case MPL_LO: type = GLP_LO; break;
+            case MPL_UP: type = GLP_UP; break;
+            case MPL_DB: type = GLP_DB; break;
+            case MPL_FX: type = GLP_FX; break;
+            default: xassert(type != type);
+         }
+         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
+         {  type = GLP_FX;
+            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
+         }
+         glp_set_row_bnds(prob, i, type, lb, ub);
+         /* warn about non-zero constant term */
+         if (mpl_get_row_c0(tran, i) != 0.0)
+            xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig"
+               "nored\n",
+               mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i));
+      }
+      /* build columns (variables) */
+      n = mpl_get_num_cols(tran);
+      if (n > 0)
+         glp_add_cols(prob, n);
+      for (j = 1; j <= n; j++)
+      {  /* set column name */
+         glp_set_col_name(prob, j, mpl_get_col_name(tran, j));
+         /* set column kind */
+         kind = mpl_get_col_kind(tran, j);
+         switch (kind)
+         {  case MPL_NUM:
+               break;
+            case MPL_INT:
+            case MPL_BIN:
+               glp_set_col_kind(prob, j, GLP_IV);
+               break;
+            default:
+               xassert(kind != kind);
+         }
+         /* set column bounds */
+         type = mpl_get_col_bnds(tran, j, &lb, &ub);
+         switch (type)
+         {  case MPL_FR: type = GLP_FR; break;
+            case MPL_LO: type = GLP_LO; break;
+            case MPL_UP: type = GLP_UP; break;
+            case MPL_DB: type = GLP_DB; break;
+            case MPL_FX: type = GLP_FX; break;
+            default: xassert(type != type);
+         }
+         if (kind == MPL_BIN)
+         {  if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0;
+            if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0;
+            type = GLP_DB;
+         }
+         if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb)))
+         {  type = GLP_FX;
+            if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub;
+         }
+         glp_set_col_bnds(prob, j, type, lb, ub);
+      }
+      /* load the constraint matrix */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  len = mpl_get_mat_row(tran, i, ind, val);
+         glp_set_mat_row(prob, i, len, ind, val);
+      }
+      /* build objective function (the first objective is used) */
+      for (i = 1; i <= m; i++)
+      {  kind = mpl_get_row_kind(tran, i);
+         if (kind == MPL_MIN || kind == MPL_MAX)
+         {  /* set objective name */
+            glp_set_obj_name(prob, mpl_get_row_name(tran, i));
+            /* set optimization direction */
+            glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX);
+            /* set constant term */
+            glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i));
+            /* set objective coefficients */
+            len = mpl_get_mat_row(tran, i, ind, val);
+            for (t = 1; t <= len; t++)
+               glp_set_obj_coef(prob, ind[t], val[t]);
+            break;
+         }
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol)
+{     /* postsolve the model */
+      int i, j, m, n, stat, ret;
+      double prim, dual;
+      if (!(tran->phase == 3 && !tran->flag_p))
+         xerror("glp_mpl_postsolve: invalid call sequence\n");
+      if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP))
+         xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n",
+            sol);
+      m = mpl_get_num_rows(tran);
+      n = mpl_get_num_cols(tran);
+      if (!(m == glp_get_num_rows(prob) &&
+            n == glp_get_num_cols(prob)))
+         xerror("glp_mpl_postsolve: wrong problem object\n");
+      if (!mpl_has_solve_stmt(tran))
+      {  ret = 0;
+         goto done;
+      }
+      for (i = 1; i <= m; i++)
+      {  if (sol == GLP_SOL)
+         {  stat = glp_get_row_stat(prob, i);
+            prim = glp_get_row_prim(prob, i);
+            dual = glp_get_row_dual(prob, i);
+         }
+         else if (sol == GLP_IPT)
+         {  stat = 0;
+            prim = glp_ipt_row_prim(prob, i);
+            dual = glp_ipt_row_dual(prob, i);
+         }
+         else if (sol == GLP_MIP)
+         {  stat = 0;
+            prim = glp_mip_row_val(prob, i);
+            dual = 0.0;
+         }
+         else
+            xassert(sol != sol);
+         if (fabs(prim) < 1e-9) prim = 0.0;
+         if (fabs(dual) < 1e-9) dual = 0.0;
+         mpl_put_row_soln(tran, i, stat, prim, dual);
+      }
+      for (j = 1; j <= n; j++)
+      {  if (sol == GLP_SOL)
+         {  stat = glp_get_col_stat(prob, j);
+            prim = glp_get_col_prim(prob, j);
+            dual = glp_get_col_dual(prob, j);
+         }
+         else if (sol == GLP_IPT)
+         {  stat = 0;
+            prim = glp_ipt_col_prim(prob, j);
+            dual = glp_ipt_col_dual(prob, j);
+         }
+         else if (sol == GLP_MIP)
+         {  stat = 0;
+            prim = glp_mip_col_val(prob, j);
+            dual = 0.0;
+         }
+         else
+            xassert(sol != sol);
+         if (fabs(prim) < 1e-9) prim = 0.0;
+         if (fabs(dual) < 1e-9) dual = 0.0;
+         mpl_put_col_soln(tran, j, stat, prim, dual);
+      }
+      ret = mpl_postsolve(tran);
+      if (ret == 3)
+         ret = 0;
+      else if (ret == 4)
+         ret = 1;
+done: return ret;
+}
+
+void glp_mpl_free_wksp(glp_tran *tran)
+{     /* free the MathProg translator workspace */
+      mpl_terminate(tran);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi15.c
===================================================================
--- deps/glpk/src/glpapi15.c	(revision 9)
+++ deps/glpk/src/glpapi15.c	(revision 9)
@@ -0,0 +1,609 @@
+/* glpapi15.c (basic graph and network routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
+
+#define NV_MAX 100000000 /* = 100*10^6 */
+/* maximal number of vertices in the graph */
+
+#define NA_MAX 500000000 /* = 500*10^6 */
+/* maximal number of arcs in the graph */
+
+/***********************************************************************
+*  NAME
+*
+*  glp_create_graph - create graph
+*
+*  SYNOPSIS
+*
+*  glp_graph *glp_create_graph(int v_size, int a_size);
+*
+*  DESCRIPTION
+*
+*  The routine creates a new graph, which initially is empty, i.e. has
+*  no vertices and arcs.
+*
+*  The parameter v_size specifies the size of data associated with each
+*  vertex of the graph (0 to 256 bytes).
+*
+*  The parameter a_size specifies the size of data associated with each
+*  arc of the graph (0 to 256 bytes).
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the graph created. */
+
+static void create_graph(glp_graph *G, int v_size, int a_size)
+{     G->pool = dmp_create_pool();
+      G->name = NULL;
+      G->nv_max = 50;
+      G->nv = G->na = 0;
+      G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
+      G->index = NULL;
+      G->v_size = v_size;
+      G->a_size = a_size;
+      return;
+}
+
+glp_graph *glp_create_graph(int v_size, int a_size)
+{     glp_graph *G;
+      if (!(0 <= v_size && v_size <= 256))
+         xerror("glp_create_graph: v_size = %d; invalid size of vertex "
+            "data\n", v_size);
+      if (!(0 <= a_size && a_size <= 256))
+         xerror("glp_create_graph: a_size = %d; invalid size of arc dat"
+            "a\n", a_size);
+      G = xmalloc(sizeof(glp_graph));
+      create_graph(G, v_size, a_size);
+      return G;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_set_graph_name - assign (change) graph name
+*
+*  SYNOPSIS
+*
+*  void glp_set_graph_name(glp_graph *G, const char *name);
+*
+*  DESCRIPTION
+*
+*  The routine glp_set_graph_name assigns a symbolic name specified by
+*  the character string name (1 to 255 chars) to the graph.
+*
+*  If the parameter name is NULL or an empty string, the routine erases
+*  the existing symbolic name of the graph. */
+
+void glp_set_graph_name(glp_graph *G, const char *name)
+{     if (G->name != NULL)
+      {  dmp_free_atom(G->pool, G->name, strlen(G->name)+1);
+         G->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int j;
+         for (j = 0; name[j] != '\0'; j++)
+         {  if (j == 256)
+               xerror("glp_set_graph_name: graph name too long\n");
+            if (iscntrl((unsigned char)name[j]))
+               xerror("glp_set_graph_name: graph name contains invalid "
+                  "character(s)\n");
+         }
+         G->name = dmp_get_atom(G->pool, strlen(name)+1);
+         strcpy(G->name, name);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_vertices - add new vertices to graph
+*
+*  SYNOPSIS
+*
+*  int glp_add_vertices(glp_graph *G, int nadd);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_vertices adds nadd vertices to the specified
+*  graph. New vertices are always added to the end of the vertex list,
+*  so ordinal numbers of existing vertices remain unchanged.
+*
+*  Being added each new vertex is isolated (has no incident arcs).
+*
+*  RETURNS
+*
+*  The routine glp_add_vertices returns an ordinal number of the first
+*  new vertex added to the graph. */
+
+int glp_add_vertices(glp_graph *G, int nadd)
+{     int i, nv_new;
+      if (nadd < 1)
+         xerror("glp_add_vertices: nadd = %d; invalid number of vertice"
+            "s\n", nadd);
+      if (nadd > NV_MAX - G->nv)
+         xerror("glp_add_vertices: nadd = %d; too many vertices\n",
+            nadd);
+      /* determine new number of vertices */
+      nv_new = G->nv + nadd;
+      /* increase the room, if necessary */
+      if (G->nv_max < nv_new)
+      {  glp_vertex **save = G->v;
+         while (G->nv_max < nv_new)
+         {  G->nv_max += G->nv_max;
+            xassert(G->nv_max > 0);
+         }
+         G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *));
+         memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *));
+         xfree(save);
+      }
+      /* add new vertices to the end of the vertex list */
+      for (i = G->nv+1; i <= nv_new; i++)
+      {  glp_vertex *v;
+         G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex));
+         v->i = i;
+         v->name = NULL;
+         v->entry = NULL;
+         if (G->v_size == 0)
+            v->data = NULL;
+         else
+         {  v->data = dmp_get_atom(G->pool, G->v_size);
+            memset(v->data, 0, G->v_size);
+         }
+         v->temp = NULL;
+         v->in = v->out = NULL;
+      }
+      /* set new number of vertices */
+      G->nv = nv_new;
+      /* return the ordinal number of the first vertex added */
+      return nv_new - nadd + 1;
+}
+
+/**********************************************************************/
+
+void glp_set_vertex_name(glp_graph *G, int i, const char *name)
+{     /* assign (change) vertex name */
+      glp_vertex *v;
+      if (!(1 <= i && i <= G->nv))
+         xerror("glp_set_vertex_name: i = %d; vertex number out of rang"
+            "e\n", i);
+      v = G->v[i];
+      if (v->name != NULL)
+      {  if (v->entry != NULL)
+         {  xassert(G->index != NULL);
+            avl_delete_node(G->index, v->entry);
+            v->entry = NULL;
+         }
+         dmp_free_atom(G->pool, v->name, strlen(v->name)+1);
+         v->name = NULL;
+      }
+      if (!(name == NULL || name[0] == '\0'))
+      {  int k;
+         for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_set_vertex_name: i = %d; vertex name too lon"
+                  "g\n", i);
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_set_vertex_name: i = %d; vertex name contain"
+                  "s invalid character(s)\n", i);
+         }
+         v->name = dmp_get_atom(G->pool, strlen(name)+1);
+         strcpy(v->name, name);
+         if (G->index != NULL)
+         {  xassert(v->entry == NULL);
+            v->entry = avl_insert_node(G->index, v->name);
+            avl_set_node_link(v->entry, v);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_add_arc - add new arc to graph
+*
+*  SYNOPSIS
+*
+*  glp_arc *glp_add_arc(glp_graph *G, int i, int j);
+*
+*  DESCRIPTION
+*
+*  The routine glp_add_arc adds a new arc to the specified graph.
+*
+*  The parameters i and j specify the ordinal numbers of, resp., tail
+*  and head vertices of the arc. Note that self-loops and multiple arcs
+*  are allowed.
+*
+*  RETURNS
+*
+*  The routine glp_add_arc returns a pointer to the arc added. */
+
+glp_arc *glp_add_arc(glp_graph *G, int i, int j)
+{     glp_arc *a;
+      if (!(1 <= i && i <= G->nv))
+         xerror("glp_add_arc: i = %d; tail vertex number out of range\n"
+            , i);
+      if (!(1 <= j && j <= G->nv))
+         xerror("glp_add_arc: j = %d; head vertex number out of range\n"
+            , j);
+      if (G->na == NA_MAX)
+         xerror("glp_add_arc: too many arcs\n");
+      a = dmp_get_atom(G->pool, sizeof(glp_arc));
+      a->tail = G->v[i];
+      a->head = G->v[j];
+      if (G->a_size == 0)
+         a->data = NULL;
+      else
+      {  a->data = dmp_get_atom(G->pool, G->a_size);
+         memset(a->data, 0, G->a_size);
+      }
+      a->temp = NULL;
+      a->t_prev = NULL;
+      a->t_next = G->v[i]->out;
+      if (a->t_next != NULL) a->t_next->t_prev = a;
+      a->h_prev = NULL;
+      a->h_next = G->v[j]->in;
+      if (a->h_next != NULL) a->h_next->h_prev = a;
+      G->v[i]->out = G->v[j]->in = a;
+      G->na++;
+      return a;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_vertices - delete vertices from graph
+*
+*  SYNOPSIS
+*
+*  void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_vertices deletes vertices along with all
+*  incident arcs from the specified graph. Ordinal numbers of vertices
+*  to be deleted should be placed in locations num[1], ..., num[ndel],
+*  ndel > 0.
+*
+*  Note that deleting vertices involves changing ordinal numbers of
+*  other vertices remaining in the graph. New ordinal numbers of the
+*  remaining vertices are assigned under the assumption that the
+*  original order of vertices is not changed. */
+
+void glp_del_vertices(glp_graph *G, int ndel, const int num[])
+{     glp_vertex *v;
+      int i, k, nv_new;
+      /* scan the list of vertices to be deleted */
+      if (!(1 <= ndel && ndel <= G->nv))
+         xerror("glp_del_vertices: ndel = %d; invalid number of vertice"
+            "s\n", ndel);
+      for (k = 1; k <= ndel; k++)
+      {  /* take the number of vertex to be deleted */
+         i = num[k];
+         /* obtain pointer to i-th vertex */
+         if (!(1 <= i && i <= G->nv))
+            xerror("glp_del_vertices: num[%d] = %d; vertex number out o"
+               "f range\n", k, i);
+         v = G->v[i];
+         /* check that the vertex is not marked yet */
+         if (v->i == 0)
+            xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu"
+               "mbers not allowed\n", k, i);
+         /* erase symbolic name assigned to the vertex */
+         glp_set_vertex_name(G, i, NULL);
+         xassert(v->name == NULL);
+         xassert(v->entry == NULL);
+         /* free vertex data, if allocated */
+         if (v->data != NULL)
+            dmp_free_atom(G->pool, v->data, G->v_size);
+         /* delete all incoming arcs */
+         while (v->in != NULL)
+            glp_del_arc(G, v->in);
+         /* delete all outgoing arcs */
+         while (v->out != NULL)
+            glp_del_arc(G, v->out);
+         /* mark the vertex to be deleted */
+         v->i = 0;
+      }
+      /* delete all marked vertices from the vertex list */
+      nv_new = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  /* obtain pointer to i-th vertex */
+         v = G->v[i];
+         /* check if the vertex is marked */
+         if (v->i == 0)
+         {  /* it is marked, delete it */
+            dmp_free_atom(G->pool, v, sizeof(glp_vertex));
+         }
+         else
+         {  /* it is not marked, keep it */
+            v->i = ++nv_new;
+            G->v[v->i] = v;
+         }
+      }
+      /* set new number of vertices in the graph */
+      G->nv = nv_new;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_del_arc - delete arc from graph
+*
+*  SYNOPSIS
+*
+*  void glp_del_arc(glp_graph *G, glp_arc *a);
+*
+*  DESCRIPTION
+*
+*  The routine glp_del_arc deletes an arc from the specified graph.
+*  The arc to be deleted must exist. */
+
+void glp_del_arc(glp_graph *G, glp_arc *a)
+{     /* some sanity checks */
+      xassert(G->na > 0);
+      xassert(1 <= a->tail->i && a->tail->i <= G->nv);
+      xassert(a->tail == G->v[a->tail->i]);
+      xassert(1 <= a->head->i && a->head->i <= G->nv);
+      xassert(a->head == G->v[a->head->i]);
+      /* remove the arc from the list of incoming arcs */
+      if (a->h_prev == NULL)
+         a->head->in = a->h_next;
+      else
+         a->h_prev->h_next = a->h_next;
+      if (a->h_next == NULL)
+         ;
+      else
+         a->h_next->h_prev = a->h_prev;
+      /* remove the arc from the list of outgoing arcs */
+      if (a->t_prev == NULL)
+         a->tail->out = a->t_next;
+      else
+         a->t_prev->t_next = a->t_next;
+      if (a->t_next == NULL)
+         ;
+      else
+         a->t_next->t_prev = a->t_prev;
+      /* free arc data, if allocated */
+      if (a->data != NULL)
+         dmp_free_atom(G->pool, a->data, G->a_size);
+      /* delete the arc from the graph */
+      dmp_free_atom(G->pool, a, sizeof(glp_arc));
+      G->na--;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_erase_graph - erase graph content
+*
+*  SYNOPSIS
+*
+*  void glp_erase_graph(glp_graph *G, int v_size, int a_size);
+*
+*  DESCRIPTION
+*
+*  The routine glp_erase_graph erases the content of the specified
+*  graph. The effect of this operation is the same as if the graph
+*  would be deleted with the routine glp_delete_graph and then created
+*  anew with the routine glp_create_graph, with exception that the
+*  handle (pointer) to the graph remains valid. */
+
+static void delete_graph(glp_graph *G)
+{     dmp_delete_pool(G->pool);
+      xfree(G->v);
+      if (G->index != NULL) avl_delete_tree(G->index);
+      return;
+}
+
+void glp_erase_graph(glp_graph *G, int v_size, int a_size)
+{     if (!(0 <= v_size && v_size <= 256))
+         xerror("glp_erase_graph: v_size = %d; invalid size of vertex d"
+            "ata\n", v_size);
+      if (!(0 <= a_size && a_size <= 256))
+         xerror("glp_erase_graph: a_size = %d; invalid size of arc data"
+            "\n", a_size);
+      delete_graph(G);
+      create_graph(G, v_size, a_size);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_delete_graph - delete graph
+*
+*  SYNOPSIS
+*
+*  void glp_delete_graph(glp_graph *G);
+*
+*  DESCRIPTION
+*
+*  The routine glp_delete_graph deletes the specified graph and frees
+*  all the memory allocated to this program object. */
+
+void glp_delete_graph(glp_graph *G)
+{     delete_graph(G);
+      xfree(G);
+      return;
+}
+
+/**********************************************************************/
+
+void glp_create_v_index(glp_graph *G)
+{     /* create vertex name index */
+      glp_vertex *v;
+      int i;
+      if (G->index == NULL)
+      {  G->index = avl_create_tree(avl_strcmp, NULL);
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            xassert(v->entry == NULL);
+            if (v->name != NULL)
+            {  v->entry = avl_insert_node(G->index, v->name);
+               avl_set_node_link(v->entry, v);
+            }
+         }
+      }
+      return;
+}
+
+int glp_find_vertex(glp_graph *G, const char *name)
+{     /* find vertex by its name */
+      AVLNODE *node;
+      int i = 0;
+      if (G->index == NULL)
+         xerror("glp_find_vertex: vertex name index does not exist\n");
+      if (!(name == NULL || name[0] == '\0' || strlen(name) > 255))
+      {  node = avl_find_node(G->index, name);
+         if (node != NULL)
+            i = ((glp_vertex *)avl_get_node_link(node))->i;
+      }
+      return i;
+}
+
+void glp_delete_v_index(glp_graph *G)
+{     /* delete vertex name index */
+      int i;
+      if (G->index != NULL)
+      {  avl_delete_tree(G->index), G->index = NULL;
+         for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_graph - read graph from plain text file
+*
+*  SYNOPSIS
+*
+*  int glp_read_graph(glp_graph *G, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_graph reads a graph from a plain text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_graph(glp_graph *G, const char *fname)
+{     glp_data *data;
+      jmp_buf jump;
+      int nv, na, i, j, k, ret;
+      glp_erase_graph(G, G->v_size, G->a_size);
+      xprintf("Reading graph from `%s'...\n", fname);
+      data = glp_sdf_open_file(fname);
+      if (data == NULL)
+      {  ret = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  ret = 1;
+         goto done;
+      }
+      glp_sdf_set_jump(data, jump);
+      nv = glp_sdf_read_int(data);
+      if (nv < 0)
+         glp_sdf_error(data, "invalid number of vertices\n");
+      na = glp_sdf_read_int(data);
+      if (na < 0)
+         glp_sdf_error(data, "invalid number of arcs\n");
+      xprintf("Graph has %d vert%s and %d arc%s\n",
+         nv, nv == 1 ? "ex" : "ices", na, na == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      for (k = 1; k <= na; k++)
+      {  i = glp_sdf_read_int(data);
+         if (!(1 <= i && i <= nv))
+            glp_sdf_error(data, "tail vertex number out of range\n");
+         j = glp_sdf_read_int(data);
+         if (!(1 <= j && j <= nv))
+            glp_sdf_error(data, "head vertex number out of range\n");
+         glp_add_arc(G, i, j);
+      }
+      xprintf("%d lines were read\n", glp_sdf_line(data));
+      ret = 0;
+done: if (data != NULL) glp_sdf_close_file(data);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_graph - write graph to plain text file
+*
+*  SYNOPSIS
+*
+*  int glp_write_graph(glp_graph *G, const char *fname).
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_graph writes the specified graph to a plain
+*  text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_graph(glp_graph *G, const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, count, ret;
+      xprintf("Writing graph to `%s'...\n", fname);
+      fp = xfopen(fname, "w"), count = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "%d %d\n", G->nv, G->na), count++;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+            xfprintf(fp, "%d %d\n", a->tail->i, a->head->i), count++;
+      }
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi16.c
===================================================================
--- deps/glpk/src/glpapi16.c	(revision 9)
+++ deps/glpk/src/glpapi16.c	(revision 9)
@@ -0,0 +1,329 @@
+/* glpapi16.c (graph and network analysis routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_weak_comp - find all weakly connected components of graph
+*
+*  SYNOPSIS
+*
+*  int glp_weak_comp(glp_graph *G, int v_num);
+*
+*  DESCRIPTION
+*
+*  The routine glp_weak_comp finds all weakly connected components of
+*  the specified graph.
+*
+*  The parameter v_num specifies an offset of the field of type int
+*  in the vertex data block, to which the routine stores the number of
+*  a (weakly) connected component containing that vertex. If v_num < 0,
+*  no component numbers are stored.
+*
+*  The components are numbered in arbitrary order from 1 to nc, where
+*  nc is the total number of components found, 0 <= nc <= |V|.
+*
+*  RETURNS
+*
+*  The routine returns nc, the total number of components found. */
+
+int glp_weak_comp(glp_graph *G, int v_num)
+{     glp_vertex *v;
+      glp_arc *a;
+      int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
+      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+         xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
+      nv = G->nv;
+      if (nv == 0)
+      {  nc = 0;
+         goto done;
+      }
+      /* allocate working arrays */
+      prev = xcalloc(1+nv, sizeof(int));
+      next = xcalloc(1+nv, sizeof(int));
+      list = xcalloc(1+nv, sizeof(int));
+      /* if vertex i is unlabelled, prev[i] is the index of previous
+         unlabelled vertex, and next[i] is the index of next unlabelled
+         vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
+         is the connected component number */
+      /* initially all vertices are unlabelled */
+      f = 1;
+      for (i = 1; i <= nv; i++)
+         prev[i] = i - 1, next[i] = i + 1;
+      next[nv] = 0;
+      /* main loop (until all vertices have been labelled) */
+      nc = 0;
+      while (f != 0)
+      {  /* take an unlabelled vertex */
+         i = f;
+         /* and remove it from the list of unlabelled vertices */
+         f = next[i];
+         if (f != 0) prev[f] = 0;
+         /* label the vertex; it begins a new component */
+         prev[i] = -1, next[i] = ++nc;
+         /* breadth first search */
+         list[1] = i, pos1 = pos2 = 1;
+         while (pos1 <= pos2)
+         {  /* dequeue vertex i */
+            i = list[pos1++];
+            /* consider all arcs incoming to vertex i */
+            for (a = G->v[i]->in; a != NULL; a = a->h_next)
+            {  /* vertex j is adjacent to vertex i */
+               j = a->tail->i;
+               if (prev[j] >= 0)
+               {  /* vertex j is unlabelled */
+                  /* remove it from the list of unlabelled vertices */
+                  if (prev[j] == 0)
+                     f = next[j];
+                  else
+                     next[prev[j]] = next[j];
+                  if (next[j] == 0)
+                     ;
+                  else
+                     prev[next[j]] = prev[j];
+                  /* label the vertex */
+                  prev[j] = -1, next[j] = nc;
+                  /* and enqueue it for further consideration */
+                  list[++pos2] = j;
+               }
+            }
+            /* consider all arcs outgoing from vertex i */
+            for (a = G->v[i]->out; a != NULL; a = a->t_next)
+            {  /* vertex j is adjacent to vertex i */
+               j = a->head->i;
+               if (prev[j] >= 0)
+               {  /* vertex j is unlabelled */
+                  /* remove it from the list of unlabelled vertices */
+                  if (prev[j] == 0)
+                     f = next[j];
+                  else
+                     next[prev[j]] = next[j];
+                  if (next[j] == 0)
+                     ;
+                  else
+                     prev[next[j]] = prev[j];
+                  /* label the vertex */
+                  prev[j] = -1, next[j] = nc;
+                  /* and enqueue it for further consideration */
+                  list[++pos2] = j;
+               }
+            }
+         }
+      }
+      /* store component numbers */
+      if (v_num >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_num, &next[i], sizeof(int));
+         }
+      }
+      /* free working arrays */
+      xfree(prev);
+      xfree(next);
+      xfree(list);
+done: return nc;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_strong_comp - find all strongly connected components of graph
+*
+*  SYNOPSIS
+*
+*  int glp_strong_comp(glp_graph *G, int v_num);
+*
+*  DESCRIPTION
+*
+*  The routine glp_strong_comp finds all strongly connected components
+*  of the specified graph.
+*
+*  The parameter v_num specifies an offset of the field of type int
+*  in the vertex data block, to which the routine stores the number of
+*  a strongly connected component containing that vertex. If v_num < 0,
+*  no component numbers are stored.
+*
+*  The components are numbered in arbitrary order from 1 to nc, where
+*  nc is the total number of components found, 0 <= nc <= |V|. However,
+*  the component numbering has the property that for every arc (i->j)
+*  in the graph the condition num(i) >= num(j) holds.
+*
+*  RETURNS
+*
+*  The routine returns nc, the total number of components found. */
+
+int glp_strong_comp(glp_graph *G, int v_num)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
+         *numb, *prev;
+      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+         xerror("glp_strong_comp: v_num = %d; invalid offset\n",
+            v_num);
+      n = G->nv;
+      if (n == 0)
+      {  nc = 0;
+         goto done;
+      }
+      na = G->na;
+      icn = xcalloc(1+na, sizeof(int));
+      ip = xcalloc(1+n, sizeof(int));
+      lenr = xcalloc(1+n, sizeof(int));
+      ior = xcalloc(1+n, sizeof(int));
+      ib = xcalloc(1+n, sizeof(int));
+      lowl = xcalloc(1+n, sizeof(int));
+      numb = xcalloc(1+n, sizeof(int));
+      prev = xcalloc(1+n, sizeof(int));
+      k = 1;
+      for (i = 1; i <= n; i++)
+      {  v = G->v[i];
+         ip[i] = k;
+         for (a = v->out; a != NULL; a = a->t_next)
+            icn[k++] = a->head->i;
+         lenr[i] = k - ip[i];
+      }
+      xassert(na == k-1);
+      nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
+      if (v_num >= 0)
+      {  xassert(ib[1] == 1);
+         for (k = 1; k <= nc; k++)
+         {  last = (k < nc ? ib[k+1] : n+1);
+            xassert(ib[k] < last);
+            for (i = ib[k]; i < last; i++)
+            {  v = G->v[ior[i]];
+               memcpy((char *)v->data + v_num, &k, sizeof(int));
+            }
+         }
+      }
+      xfree(icn);
+      xfree(ip);
+      xfree(lenr);
+      xfree(ior);
+      xfree(ib);
+      xfree(lowl);
+      xfree(numb);
+      xfree(prev);
+done: return nc;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_top_sort - topological sorting of acyclic digraph
+*
+*  SYNOPSIS
+*
+*  int glp_top_sort(glp_graph *G, int v_num);
+*
+*  DESCRIPTION
+*
+*  The routine glp_top_sort performs topological sorting of vertices of
+*  the specified acyclic digraph.
+*
+*  The parameter v_num specifies an offset of the field of type int in
+*  the vertex data block, to which the routine stores the vertex number
+*  assigned. If v_num < 0, vertex numbers are not stored.
+*
+*  The vertices are numbered from 1 to n, where n is the total number
+*  of vertices in the graph. The vertex numbering has the property that
+*  for every arc (i->j) in the graph the condition num(i) < num(j)
+*  holds. Special case num(i) = 0 means that vertex i is not assigned a
+*  number, because the graph is *not* acyclic.
+*
+*  RETURNS
+*
+*  If the graph is acyclic and therefore all the vertices have been
+*  assigned numbers, the routine glp_top_sort returns zero. Otherwise,
+*  if the graph is not acyclic, the routine returns the number of
+*  vertices which have not been numbered, i.e. for which num(i) = 0. */
+
+static int top_sort(glp_graph *G, int num[])
+{     glp_arc *a;
+      int i, j, cnt, top, *stack, *indeg;
+      /* allocate working arrays */
+      indeg = xcalloc(1+G->nv, sizeof(int));
+      stack = xcalloc(1+G->nv, sizeof(int));
+      /* determine initial indegree of each vertex; push into the stack
+         the vertices having zero indegree */
+      top = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  num[i] = indeg[i] = 0;
+         for (a = G->v[i]->in; a != NULL; a = a->h_next)
+            indeg[i]++;
+         if (indeg[i] == 0)
+            stack[++top] = i;
+      }
+      /* assign numbers to vertices in the sorted order */
+      cnt = 0;
+      while (top > 0)
+      {  /* pull vertex i from the stack */
+         i = stack[top--];
+         /* it has zero indegree in the current graph */
+         xassert(indeg[i] == 0);
+         /* so assign it a next number */
+         xassert(num[i] == 0);
+         num[i] = ++cnt;
+         /* remove vertex i from the current graph, update indegree of
+            its adjacent vertices, and push into the stack new vertices
+            whose indegree becomes zero */
+         for (a = G->v[i]->out; a != NULL; a = a->t_next)
+         {  j = a->head->i;
+            /* there exists arc (i->j) in the graph */
+            xassert(indeg[j] > 0);
+            indeg[j]--;
+            if (indeg[j] == 0)
+               stack[++top] = j;
+         }
+      }
+      /* free working arrays */
+      xfree(indeg);
+      xfree(stack);
+      return G->nv - cnt;
+}
+
+int glp_top_sort(glp_graph *G, int v_num)
+{     glp_vertex *v;
+      int i, cnt, *num;
+      if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
+         xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
+      if (G->nv == 0)
+      {  cnt = 0;
+         goto done;
+      }
+      num = xcalloc(1+G->nv, sizeof(int));
+      cnt = top_sort(G, num);
+      if (v_num >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_num, &num[i], sizeof(int));
+         }
+      }
+      xfree(num);
+done: return cnt;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi17.c
===================================================================
--- deps/glpk/src/glpapi17.c	(revision 9)
+++ deps/glpk/src/glpapi17.c	(revision 9)
@@ -0,0 +1,1048 @@
+/* glpapi17.c (flow network problems) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mincost_lp - convert minimum cost flow problem to LP
+*
+*  SYNOPSIS
+*
+*  void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names,
+*     int v_rhs, int a_low, int a_cap, int a_cost);
+*
+*  DESCRIPTION
+*
+*  The routine glp_mincost_lp builds an LP problem, which corresponds
+*  to the minimum cost flow problem on the specified network G. */
+
+void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs,
+      int a_low, int a_cap, int a_cost)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, type, ind[1+2];
+      double rhs, low, cap, cost, val[1+2];
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_mincost_lp: names = %d; invalid parameter\n",
+            names);
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost)
+            ;
+      glp_erase_prob(lp);
+      if (names) glp_set_prob_name(lp, G->name);
+      if (G->nv > 0) glp_add_rows(lp, G->nv);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (names) glp_set_row_name(lp, i, v->name);
+         if (v_rhs >= 0)
+            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
+         else
+            rhs = 0.0;
+         glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs);
+      }
+      if (G->na > 0) glp_add_cols(lp, G->na);
+      for (i = 1, j = 0; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  j++;
+            if (names)
+            {  char name[50+1];
+               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+               xassert(strlen(name) < sizeof(name));
+               glp_set_col_name(lp, j, name);
+            }
+            if (a->tail->i != a->head->i)
+            {  ind[1] = a->tail->i, val[1] = +1.0;
+               ind[2] = a->head->i, val[2] = -1.0;
+               glp_set_mat_col(lp, j, 2, ind, val);
+            }
+            if (a_low >= 0)
+               memcpy(&low, (char *)a->data + a_low, sizeof(double));
+            else
+               low = 0.0;
+            if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            if (cap == DBL_MAX)
+               type = GLP_LO;
+            else if (low != cap)
+               type = GLP_DB;
+            else
+               type = GLP_FX;
+            glp_set_col_bnds(lp, j, type, low, cap);
+            if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 0.0;
+            glp_set_obj_coef(lp, j, cost);
+         }
+      }
+      xassert(j == G->na);
+      return;
+}
+
+/**********************************************************************/
+
+int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, double *sol, int a_x, int v_pi)
+{     /* find minimum-cost flow with out-of-kilter algorithm */
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi,
+         ret;
+      double sum, temp;
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n",
+            v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_low = %d; invalid offset\n",
+            a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n",
+            a_cost);
+      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x);
+      if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double))
+         xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi);
+      /* s is artificial source node */
+      s = G->nv + 1;
+      /* t is artificial sink node */
+      t = s + 1;
+      /* nv is the total number of nodes in the resulting network */
+      nv = t;
+      /* na is the total number of arcs in the resulting network */
+      na = G->na + 1;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_rhs >= 0)
+            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
+         else
+            temp = 0.0;
+         if (temp != 0.0) na++;
+      }
+      /* allocate working arrays */
+      tail = xcalloc(1+na, sizeof(int));
+      head = xcalloc(1+na, sizeof(int));
+      low = xcalloc(1+na, sizeof(int));
+      cap = xcalloc(1+na, sizeof(int));
+      cost = xcalloc(1+na, sizeof(int));
+      x = xcalloc(1+na, sizeof(int));
+      pi = xcalloc(1+nv, sizeof(int));
+      /* construct the resulting network */
+      k = 0;
+      /* (original arcs) */
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  k++;
+            tail[k] = a->tail->i;
+            head[k] = a->head->i;
+            if (tail[k] == head[k])
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            if (a_low >= 0)
+               memcpy(&temp, (char *)a->data + a_low, sizeof(double));
+            else
+               temp = 0.0;
+            if (!(0.0 <= temp && temp <= (double)INT_MAX &&
+                  temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            low[k] = (int)temp;
+            if (a_cap >= 0)
+               memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
+            else
+               temp = 1.0;
+            if (!((double)low[k] <= temp && temp <= (double)INT_MAX &&
+                  temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cap[k] = (int)temp;
+            if (a_cost >= 0)
+               memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
+            else
+               temp = 0.0;
+            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cost[k] = (int)temp;
+         }
+      }
+      /* (artificial arcs) */
+      sum = 0.0;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_rhs >= 0)
+            memcpy(&temp, (char *)v->data + v_rhs, sizeof(double));
+         else
+            temp = 0.0;
+         if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+         {  ret = GLP_EDATA;
+            goto done;
+         }
+         if (temp > 0.0)
+         {  /* artificial arc from s to original source i */
+            k++;
+            tail[k] = s;
+            head[k] = i;
+            low[k] = cap[k] = (int)(+temp); /* supply */
+            cost[k] = 0;
+            sum += (double)temp;
+         }
+         else if (temp < 0.0)
+         {  /* artificial arc from original sink i to t */
+            k++;
+            tail[k] = i;
+            head[k] = t;
+            low[k] = cap[k] = (int)(-temp); /* demand */
+            cost[k] = 0;
+         }
+      }
+      /* (feedback arc from t to s) */
+      k++;
+      xassert(k == na);
+      tail[k] = t;
+      head[k] = s;
+      if (sum > (double)INT_MAX)
+      {  ret = GLP_EDATA;
+         goto done;
+      }
+      low[k] = cap[k] = (int)sum; /* total supply/demand */
+      cost[k] = 0;
+      /* find minimal-cost circulation in the resulting network */
+      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
+      switch (ret)
+      {  case 0:
+            /* optimal circulation found */
+            ret = 0;
+            break;
+         case 1:
+            /* no feasible circulation exists */
+            ret = GLP_ENOPFS;
+            break;
+         case 2:
+            /* integer overflow occured */
+            ret = GLP_ERANGE;
+            goto done;
+         case 3:
+            /* optimality test failed (logic error) */
+            ret = GLP_EFAIL;
+            goto done;
+         default:
+            xassert(ret != ret);
+      }
+      /* store solution components */
+      /* (objective function = the total cost) */
+      if (sol != NULL)
+      {  temp = 0.0;
+         for (k = 1; k <= na; k++)
+            temp += (double)cost[k] * (double)x[k];
+         *sol = temp;
+      }
+      /* (arc flows) */
+      if (a_x >= 0)
+      {  k = 0;
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            for (a = v->out; a != NULL; a = a->t_next)
+            {  temp = (double)x[++k];
+               memcpy((char *)a->data + a_x, &temp, sizeof(double));
+            }
+         }
+      }
+      /* (node potentials = Lagrange multipliers) */
+      if (v_pi >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            temp = - (double)pi[i];
+            memcpy((char *)v->data + v_pi, &temp, sizeof(double));
+         }
+      }
+done: /* free working arrays */
+      xfree(tail);
+      xfree(head);
+      xfree(low);
+      xfree(cap);
+      xfree(cost);
+      xfree(x);
+      xfree(pi);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_maxflow_lp - convert maximum flow problem to LP
+*
+*  SYNOPSIS
+*
+*  void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
+*     int t, int a_cap);
+*
+*  DESCRIPTION
+*
+*  The routine glp_maxflow_lp builds an LP problem, which corresponds
+*  to the maximum flow problem on the specified network G. */
+
+void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s,
+      int t, int a_cap)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, type, ind[1+2];
+      double cap, val[1+2];
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_maxflow_lp: names = %d; invalid parameter\n",
+            names);
+      if (!(1 <= s && s <= G->nv))
+         xerror("glp_maxflow_lp: s = %d; source node number out of rang"
+            "e\n", s);
+      if (!(1 <= t && t <= G->nv))
+         xerror("glp_maxflow_lp: t = %d: sink node number out of range "
+            "\n", t);
+      if (s == t)
+         xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must"
+            " be distinct\n", s);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap);
+      glp_erase_prob(lp);
+      if (names) glp_set_prob_name(lp, G->name);
+      glp_set_obj_dir(lp, GLP_MAX);
+      glp_add_rows(lp, G->nv);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (names) glp_set_row_name(lp, i, v->name);
+         if (i == s)
+            type = GLP_LO;
+         else if (i == t)
+            type = GLP_UP;
+         else
+            type = GLP_FX;
+         glp_set_row_bnds(lp, i, type, 0.0, 0.0);
+      }
+      if (G->na > 0) glp_add_cols(lp, G->na);
+      for (i = 1, j = 0; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  j++;
+            if (names)
+            {  char name[50+1];
+               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+               xassert(strlen(name) < sizeof(name));
+               glp_set_col_name(lp, j, name);
+            }
+            if (a->tail->i != a->head->i)
+            {  ind[1] = a->tail->i, val[1] = +1.0;
+               ind[2] = a->head->i, val[2] = -1.0;
+               glp_set_mat_col(lp, j, 2, ind, val);
+            }
+            if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            if (cap == DBL_MAX)
+               type = GLP_LO;
+            else if (cap != 0.0)
+               type = GLP_DB;
+            else
+               type = GLP_FX;
+            glp_set_col_bnds(lp, j, type, 0.0, cap);
+            if (a->tail->i == s)
+               glp_set_obj_coef(lp, j, +1.0);
+            else if (a->head->i == s)
+               glp_set_obj_coef(lp, j, -1.0);
+         }
+      }
+      xassert(j == G->na);
+      return;
+}
+
+int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
+      double *sol, int a_x, int v_cut)
+{     /* find maximal flow with Ford-Fulkerson algorithm */
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, i, k, flag, *tail, *head, *cap, *x, ret;
+      char *cut;
+      double temp;
+      if (!(1 <= s && s <= G->nv))
+         xerror("glp_maxflow_ffalg: s = %d; source node number out of r"
+            "ange\n", s);
+      if (!(1 <= t && t <= G->nv))
+         xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran"
+            "ge\n", t);
+      if (s == t)
+         xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m"
+            "ust be distinct\n", s);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int))
+         xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n",
+            v_cut);
+      /* allocate working arrays */
+      nv = G->nv;
+      na = G->na;
+      tail = xcalloc(1+na, sizeof(int));
+      head = xcalloc(1+na, sizeof(int));
+      cap = xcalloc(1+na, sizeof(int));
+      x = xcalloc(1+na, sizeof(int));
+      if (v_cut < 0)
+         cut = NULL;
+      else
+         cut = xcalloc(1+nv, sizeof(char));
+      /* copy the flow network */
+      k = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  k++;
+            tail[k] = a->tail->i;
+            head[k] = a->head->i;
+            if (tail[k] == head[k])
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            if (a_cap >= 0)
+               memcpy(&temp, (char *)a->data + a_cap, sizeof(double));
+            else
+               temp = 1.0;
+            if (!(0.0 <= temp && temp <= (double)INT_MAX &&
+                  temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cap[k] = (int)temp;
+         }
+      }
+      xassert(k == na);
+      /* find maximal flow in the flow network */
+      ffalg(nv, na, tail, head, s, t, cap, x, cut);
+      ret = 0;
+      /* store solution components */
+      /* (objective function = total flow through the network) */
+      if (sol != NULL)
+      {  temp = 0.0;
+         for (k = 1; k <= na; k++)
+         {  if (tail[k] == s)
+               temp += (double)x[k];
+            else if (head[k] == s)
+               temp -= (double)x[k];
+         }
+         *sol = temp;
+      }
+      /* (arc flows) */
+      if (a_x >= 0)
+      {  k = 0;
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            for (a = v->out; a != NULL; a = a->t_next)
+            {  temp = (double)x[++k];
+               memcpy((char *)a->data + a_x, &temp, sizeof(double));
+            }
+         }
+      }
+      /* (node flags) */
+      if (v_cut >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            flag = cut[i];
+            memcpy((char *)v->data + v_cut, &flag, sizeof(int));
+         }
+      }
+done: /* free working arrays */
+      xfree(tail);
+      xfree(head);
+      xfree(cap);
+      xfree(x);
+      if (cut != NULL) xfree(cut);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_check_asnprob - check correctness of assignment problem data
+*
+*  SYNOPSIS
+*
+*  int glp_check_asnprob(glp_graph *G, int v_set);
+*
+*  RETURNS
+*
+*  If the specified assignment problem data are correct, the routine
+*  glp_check_asnprob returns zero, otherwise, non-zero. */
+
+int glp_check_asnprob(glp_graph *G, int v_set)
+{     glp_vertex *v;
+      int i, k, ret = 0;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_check_asnprob: v_set = %d; invalid offset\n",
+            v_set);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_set >= 0)
+         {  memcpy(&k, (char *)v->data + v_set, sizeof(int));
+            if (k == 0)
+            {  if (v->in != NULL)
+               {  ret = 1;
+                  break;
+               }
+            }
+            else if (k == 1)
+            {  if (v->out != NULL)
+               {  ret = 2;
+                  break;
+               }
+            }
+            else
+            {  ret = 3;
+               break;
+            }
+         }
+         else
+         {  if (v->in != NULL && v->out != NULL)
+            {  ret = 4;
+               break;
+            }
+         }
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_asnprob_lp - convert assignment problem to LP
+*
+*  SYNOPSIS
+*
+*  int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+*     int v_set, int a_cost);
+*
+*  DESCRIPTION
+*
+*  The routine glp_asnprob_lp builds an LP problem, which corresponds
+*  to the assignment problem on the specified graph G.
+*
+*  RETURNS
+*
+*  If the LP problem has been successfully built, the routine returns
+*  zero, otherwise, non-zero. */
+
+int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+      int v_set, int a_cost)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, ret, ind[1+2];
+      double cost, val[1+2];
+      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
+            form == GLP_ASN_MMP))
+         xerror("glp_asnprob_lp: form = %d; invalid parameter\n",
+            form);
+      if (!(names == GLP_ON || names == GLP_OFF))
+         xerror("glp_asnprob_lp: names = %d; invalid parameter\n",
+            names);
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_asnprob_lp: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n",
+            a_cost);
+      ret = glp_check_asnprob(G, v_set);
+      if (ret != 0) goto done;
+      glp_erase_prob(P);
+      if (names) glp_set_prob_name(P, G->name);
+      glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX);
+      if (G->nv > 0) glp_add_rows(P, G->nv);
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (names) glp_set_row_name(P, i, v->name);
+         glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX,
+            1.0, 1.0);
+      }
+      if (G->na > 0) glp_add_cols(P, G->na);
+      for (i = 1, j = 0; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  j++;
+            if (names)
+            {  char name[50+1];
+               sprintf(name, "x[%d,%d]", a->tail->i, a->head->i);
+               xassert(strlen(name) < sizeof(name));
+               glp_set_col_name(P, j, name);
+            }
+            ind[1] = a->tail->i, val[1] = +1.0;
+            ind[2] = a->head->i, val[2] = +1.0;
+            glp_set_mat_col(P, j, 2, ind, val);
+            glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0);
+            if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 1.0;
+            glp_set_obj_coef(P, j, cost);
+         }
+      }
+      xassert(j == G->na);
+done: return ret;
+}
+
+/**********************************************************************/
+
+int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
+      double *sol, int a_x)
+{     /* solve assignment problem with out-of-kilter algorithm */
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret;
+      double temp;
+      if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX ||
+            form == GLP_ASN_MMP))
+         xerror("glp_asnprob_okalg: form = %d; invalid parameter\n",
+            form);
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n",
+            a_cost);
+      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
+         xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x);
+      if (glp_check_asnprob(G, v_set))
+         return GLP_EDATA;
+      /* nv is the total number of nodes in the resulting network */
+      nv = G->nv + 1;
+      /* na is the total number of arcs in the resulting network */
+      na = G->na + G->nv;
+      /* allocate working arrays */
+      tail = xcalloc(1+na, sizeof(int));
+      head = xcalloc(1+na, sizeof(int));
+      low = xcalloc(1+na, sizeof(int));
+      cap = xcalloc(1+na, sizeof(int));
+      cost = xcalloc(1+na, sizeof(int));
+      x = xcalloc(1+na, sizeof(int));
+      pi = xcalloc(1+nv, sizeof(int));
+      /* construct the resulting network */
+      k = 0;
+      /* (original arcs) */
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  k++;
+            tail[k] = a->tail->i;
+            head[k] = a->head->i;
+            low[k] = 0;
+            cap[k] = 1;
+            if (a_cost >= 0)
+               memcpy(&temp, (char *)a->data + a_cost, sizeof(double));
+            else
+               temp = 1.0;
+            if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            cost[k] = (int)temp;
+            if (form != GLP_ASN_MIN) cost[k] = - cost[k];
+         }
+      }
+      /* (artificial arcs) */
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         k++;
+         if (v->out == NULL)
+            tail[k] = i, head[k] = nv;
+         else if (v->in == NULL)
+            tail[k] = nv, head[k] = i;
+         else
+            xassert(v != v);
+         low[k] = (form == GLP_ASN_MMP ? 0 : 1);
+         cap[k] = 1;
+         cost[k] = 0;
+      }
+      xassert(k == na);
+      /* find minimal-cost circulation in the resulting network */
+      ret = okalg(nv, na, tail, head, low, cap, cost, x, pi);
+      switch (ret)
+      {  case 0:
+            /* optimal circulation found */
+            ret = 0;
+            break;
+         case 1:
+            /* no feasible circulation exists */
+            ret = GLP_ENOPFS;
+            break;
+         case 2:
+            /* integer overflow occured */
+            ret = GLP_ERANGE;
+            goto done;
+         case 3:
+            /* optimality test failed (logic error) */
+            ret = GLP_EFAIL;
+            goto done;
+         default:
+            xassert(ret != ret);
+      }
+      /* store solution components */
+      /* (objective function = the total cost) */
+      if (sol != NULL)
+      {  temp = 0.0;
+         for (k = 1; k <= na; k++)
+            temp += (double)cost[k] * (double)x[k];
+         if (form != GLP_ASN_MIN) temp = - temp;
+         *sol = temp;
+      }
+      /* (arc flows) */
+      if (a_x >= 0)
+      {  k = 0;
+         for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            for (a = v->out; a != NULL; a = a->t_next)
+            {  k++;
+               if (ret == 0)
+                  xassert(x[k] == 0 || x[k] == 1);
+               memcpy((char *)a->data + a_x, &x[k], sizeof(int));
+            }
+         }
+      }
+done: /* free working arrays */
+      xfree(tail);
+      xfree(head);
+      xfree(low);
+      xfree(cap);
+      xfree(cost);
+      xfree(x);
+      xfree(pi);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_asnprob_hall - find bipartite matching of maximum cardinality
+*
+*  SYNOPSIS
+*
+*  int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
+*
+*  DESCRIPTION
+*
+*  The routine glp_asnprob_hall finds a matching of maximal cardinality
+*  in the specified bipartite graph G. It uses a version of the Fortran
+*  routine MC21A developed by I.S.Duff [1], which implements Hall's
+*  algorithm [2].
+*
+*  RETURNS
+*
+*  The routine glp_asnprob_hall returns the cardinality of the matching
+*  found. However, if the specified graph is incorrect (as detected by
+*  the routine glp_check_asnprob), the routine returns negative value.
+*
+*  REFERENCES
+*
+*  1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
+*     Trans. on Math. Softw. 7 (1981), 387-390.
+*
+*  2. M.Hall, "An Algorithm for distinct representatives," Amer. Math.
+*     Monthly 63 (1956), 716-717. */
+
+int glp_asnprob_hall(glp_graph *G, int v_set, int a_x)
+{     glp_vertex *v;
+      glp_arc *a;
+      int card, i, k, loc, n, n1, n2, xij;
+      int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_asnprob_hall: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int))
+         xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x);
+      if (glp_check_asnprob(G, v_set))
+         return -1;
+      /* determine the number of vertices in sets R and S and renumber
+         vertices in S which correspond to columns of the matrix; skip
+         all isolated vertices */
+      num = xcalloc(1+G->nv, sizeof(int));
+      n1 = n2 = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v->in == NULL && v->out != NULL)
+            n1++, num[i] = 0; /* vertex in R */
+         else if (v->in != NULL && v->out == NULL)
+            n2++, num[i] = n2; /* vertex in S */
+         else
+         {  xassert(v->in == NULL && v->out == NULL);
+            num[i] = -1; /* isolated vertex */
+         }
+      }
+      /* the matrix must be square, thus, if it has more columns than
+         rows, extra rows will be just empty, and vice versa */
+      n = (n1 >= n2 ? n1 : n2);
+      /* allocate working arrays */
+      icn = xcalloc(1+G->na, sizeof(int));
+      ip = xcalloc(1+n, sizeof(int));
+      lenr = xcalloc(1+n, sizeof(int));
+      iperm = xcalloc(1+n, sizeof(int));
+      pr = xcalloc(1+n, sizeof(int));
+      arp = xcalloc(1+n, sizeof(int));
+      cv = xcalloc(1+n, sizeof(int));
+      out = xcalloc(1+n, sizeof(int));
+      /* build the adjacency matrix of the bipartite graph in row-wise
+         format (rows are vertices in R, columns are vertices in S) */
+      k = 0, loc = 1;
+      for (i = 1; i <= G->nv; i++)
+      {  if (num[i] != 0) continue;
+         /* vertex i in R */
+         ip[++k] = loc;
+         v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  xassert(num[a->head->i] != 0);
+            icn[loc++] = num[a->head->i];
+         }
+         lenr[k] = loc - ip[k];
+      }
+      xassert(loc-1 == G->na);
+      /* make all extra rows empty (all extra columns are empty due to
+         the row-wise format used) */
+      for (k++; k <= n; k++)
+         ip[k] = loc, lenr[k] = 0;
+      /* find a row permutation that maximizes the number of non-zeros
+         on the main diagonal */
+      card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out);
+#if 1 /* 18/II-2010 */
+      /* FIXED: if card = n, arp remains clobbered on exit */
+      for (i = 1; i <= n; i++)
+         arp[i] = 0;
+      for (i = 1; i <= card; i++)
+      {  k = iperm[i];
+         xassert(1 <= k && k <= n);
+         xassert(arp[k] == 0);
+         arp[k] = i;
+      }
+#endif
+      /* store solution, if necessary */
+      if (a_x < 0) goto skip;
+      k = 0;
+      for (i = 1; i <= G->nv; i++)
+      {  if (num[i] != 0) continue;
+         /* vertex i in R */
+         k++;
+         v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  /* arp[k] is the number of matched column or zero */
+            if (arp[k] == num[a->head->i])
+            {  xassert(arp[k] != 0);
+               xij = 1;
+            }
+            else
+               xij = 0;
+            memcpy((char *)a->data + a_x, &xij, sizeof(int));
+         }
+      }
+skip: /* free working arrays */
+      xfree(num);
+      xfree(icn);
+      xfree(ip);
+      xfree(lenr);
+      xfree(iperm);
+      xfree(pr);
+      xfree(arp);
+      xfree(cv);
+      xfree(out);
+      return card;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_cpp - solve critical path problem
+*
+*  SYNOPSIS
+*
+*  double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
+*
+*  DESCRIPTION
+*
+*  The routine glp_cpp solves the critical path problem represented in
+*  the form of the project network.
+*
+*  The parameter G is a pointer to the graph object, which specifies
+*  the project network. This graph must be acyclic. Multiple arcs are
+*  allowed being considered as single arcs.
+*
+*  The parameter v_t specifies an offset of the field of type double
+*  in the vertex data block, which contains time t[i] >= 0 needed to
+*  perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1
+*  for all jobs.
+*
+*  The parameter v_es specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores earliest start
+*  time for corresponding job. If v_es < 0, this time is not stored.
+*
+*  The parameter v_ls specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores latest start
+*  time for corresponding job. If v_ls < 0, this time is not stored.
+*
+*  RETURNS
+*
+*  The routine glp_cpp returns the minimal project duration, that is,
+*  minimal time needed to perform all jobs in the project. */
+
+static void sorting(glp_graph *G, int list[]);
+
+double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls)
+{     glp_vertex *v;
+      glp_arc *a;
+      int i, j, k, nv, *list;
+      double temp, total, *t, *es, *ls;
+      if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double))
+         xerror("glp_cpp: v_t = %d; invalid offset\n", v_t);
+      if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double))
+         xerror("glp_cpp: v_es = %d; invalid offset\n", v_es);
+      if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double))
+         xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls);
+      nv = G->nv;
+      if (nv == 0)
+      {  total = 0.0;
+         goto done;
+      }
+      /* allocate working arrays */
+      t = xcalloc(1+nv, sizeof(double));
+      es = xcalloc(1+nv, sizeof(double));
+      ls = xcalloc(1+nv, sizeof(double));
+      list = xcalloc(1+nv, sizeof(int));
+      /* retrieve job times */
+      for (i = 1; i <= nv; i++)
+      {  v = G->v[i];
+         if (v_t >= 0)
+         {  memcpy(&t[i], (char *)v->data + v_t, sizeof(double));
+            if (t[i] < 0.0)
+               xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]);
+         }
+         else
+            t[i] = 1.0;
+      }
+      /* perform topological sorting to determine the list of nodes
+         (jobs) such that if list[k] = i and list[kk] = j and there
+         exists arc (i->j), then k < kk */
+      sorting(G, list);
+      /* FORWARD PASS */
+      /* determine earliest start times */
+      for (k = 1; k <= nv; k++)
+      {  j = list[k];
+         es[j] = 0.0;
+         for (a = G->v[j]->in; a != NULL; a = a->h_next)
+         {  i = a->tail->i;
+            /* there exists arc (i->j) in the project network */
+            temp = es[i] + t[i];
+            if (es[j] < temp) es[j] = temp;
+         }
+      }
+      /* determine the minimal project duration */
+      total = 0.0;
+      for (i = 1; i <= nv; i++)
+      {  temp = es[i] + t[i];
+         if (total < temp) total = temp;
+      }
+      /* BACKWARD PASS */
+      /* determine latest start times */
+      for (k = nv; k >= 1; k--)
+      {  i = list[k];
+         ls[i] = total - t[i];
+         for (a = G->v[i]->out; a != NULL; a = a->t_next)
+         {  j = a->head->i;
+            /* there exists arc (i->j) in the project network */
+            temp = ls[j] - t[i];
+            if (ls[i] > temp) ls[i] = temp;
+         }
+         /* avoid possible round-off errors */
+         if (ls[i] < es[i]) ls[i] = es[i];
+      }
+      /* store results, if necessary */
+      if (v_es >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_es, &es[i], sizeof(double));
+         }
+      }
+      if (v_ls >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_ls, &ls[i], sizeof(double));
+         }
+      }
+      /* free working arrays */
+      xfree(t);
+      xfree(es);
+      xfree(ls);
+      xfree(list);
+done: return total;
+}
+
+static void sorting(glp_graph *G, int list[])
+{     /* perform topological sorting to determine the list of nodes
+         (jobs) such that if list[k] = i and list[kk] = j and there
+         exists arc (i->j), then k < kk */
+      int i, k, nv, v_size, *num;
+      void **save;
+      nv = G->nv;
+      v_size = G->v_size;
+      save = xcalloc(1+nv, sizeof(void *));
+      num = xcalloc(1+nv, sizeof(int));
+      G->v_size = sizeof(int);
+      for (i = 1; i <= nv; i++)
+      {  save[i] = G->v[i]->data;
+         G->v[i]->data = &num[i];
+         list[i] = 0;
+      }
+      if (glp_top_sort(G, 0) != 0)
+         xerror("glp_cpp: project network is not acyclic\n");
+      G->v_size = v_size;
+      for (i = 1; i <= nv; i++)
+      {  G->v[i]->data = save[i];
+         k = num[i];
+         xassert(1 <= k && k <= nv);
+         xassert(list[k] == 0);
+         list[k] = i;
+      }
+      xfree(save);
+      xfree(num);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi18.c
===================================================================
--- deps/glpk/src/glpapi18.c	(revision 9)
+++ deps/glpk/src/glpapi18.c	(revision 9)
@@ -0,0 +1,122 @@
+/* glpapi18.c (maximum clique problem) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+static void set_edge(int nv, unsigned char a[], int i, int j)
+{     int k;
+      xassert(1 <= j && j < i && i <= nv);
+      k = ((i - 1) * (i - 2)) / 2 + (j - 1);
+      a[k / CHAR_BIT] |=
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+      return;
+}
+
+int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set)
+{     /* find maximum weight clique with exact algorithm */
+      glp_arc *e;
+      int i, j, k, len, x, *w, *ind, ret = 0;
+      unsigned char *a;
+      double s, t;
+      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+         xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n",
+            v_wgt);
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_wclique_exact: v_set = %d; invalid parameter\n",
+            v_set);
+      if (G->nv == 0)
+      {  /* empty graph has only empty clique */
+         if (sol != NULL) *sol = 0.0;
+         return 0;
+      }
+      /* allocate working arrays */
+      w = xcalloc(1+G->nv, sizeof(int));
+      ind = xcalloc(1+G->nv, sizeof(int));
+      len = G->nv; /* # vertices */
+      len = len * (len - 1) / 2; /* # entries in lower triangle */
+      len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */
+      a = xcalloc(len, sizeof(char));
+      memset(a, 0, len * sizeof(char));
+      /* determine vertex weights */
+      s = 0.0;
+      for (i = 1; i <= G->nv; i++)
+      {  if (v_wgt >= 0)
+         {  memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double));
+            if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t)))
+            {  ret = GLP_EDATA;
+               goto done;
+            }
+            w[i] = (int)t;
+         }
+         else
+            w[i] = 1;
+         s += (double)w[i];
+      }
+      if (s > (double)INT_MAX)
+      {  ret = GLP_EDATA;
+         goto done;
+      }
+      /* build the adjacency matrix */
+      for (i = 1; i <= G->nv; i++)
+      {  for (e = G->v[i]->in; e != NULL; e = e->h_next)
+         {  j = e->tail->i;
+            /* there exists edge (j,i) in the graph */
+            if (i > j) set_edge(G->nv, a, i, j);
+         }
+         for (e = G->v[i]->out; e != NULL; e = e->t_next)
+         {  j = e->head->i;
+            /* there exists edge (i,j) in the graph */
+            if (i > j) set_edge(G->nv, a, i, j);
+         }
+      }
+      /* find maximum weight clique in the graph */
+      len = wclique(G->nv, w, a, ind);
+      /* compute the clique weight */
+      s = 0.0;
+      for (k = 1; k <= len; k++)
+      {  i = ind[k];
+         xassert(1 <= i && i <= G->nv);
+         s += (double)w[i];
+      }
+      if (sol != NULL) *sol = s;
+      /* mark vertices included in the clique */
+      if (v_set >= 0)
+      {  x = 0;
+         for (i = 1; i <= G->nv; i++)
+            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
+         x = 1;
+         for (k = 1; k <= len; k++)
+         {  i = ind[k];
+            memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int));
+         }
+      }
+done: /* free working arrays */
+      xfree(w);
+      xfree(ind);
+      xfree(a);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi19.c
===================================================================
--- deps/glpk/src/glpapi19.c	(revision 9)
+++ deps/glpk/src/glpapi19.c	(revision 9)
@@ -0,0 +1,132 @@
+/* glpapi19.c (driver to MiniSat solver) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "minisat/minisat.h"
+
+int glp_minisat1(glp_prob *P)
+{     /* solve CNF-SAT problem with MiniSat solver */
+      solver *s;
+      GLPAIJ *aij;
+      int i, j, len, ret, *ind;
+      double sum;
+      /* check problem object */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_minisat1: P = %p; invalid problem object\n",
+            P);
+      if (P->tree != NULL)
+         xerror("glp_minisat1: operation not allowed\n");
+      /* integer solution is currently undefined */
+      P->mip_stat = GLP_UNDEF;
+      P->mip_obj = 0.0;
+      /* check that problem object encodes CNF-SAT instance */
+      if (glp_check_cnfsat(P) != 0)
+      {  xprintf("glp_minisat1: problem object does not encode CNF-SAT "
+            "instance\n");
+         ret = GLP_EDATA;
+         goto done;
+      }
+      /* solve CNF-SAT problem */
+      xprintf("Solving CNF-SAT problem...\n");
+      xprintf("Instance has %d variable%s, %d clause%s, and %d literal%"
+         "s\n", P->n, P->n == 1 ? "" : "s", P->m, P->m == 1 ? "" : "s",
+         P->nnz, P->nnz == 1 ? "" : "s");
+      /* if CNF-SAT has no clauses, it is satisfiable */
+      if (P->m == 0)
+      {  P->mip_stat = GLP_OPT;
+         for (j = 1; j <= P->n; j++)
+            P->col[j]->mipx = 0.0;
+         goto fini;
+      }
+      /* if CNF-SAT has an empty clause, it is unsatisfiable */
+      for (i = 1; i <= P->m; i++)
+      {  if (P->row[i]->ptr == NULL)
+         {  P->mip_stat = GLP_NOFEAS;
+            goto fini;
+         }
+      }
+      /* prepare input data for the solver */
+      s = solver_new();
+      solver_setnvars(s, P->n);
+      ind = xcalloc(1+P->n, sizeof(int));
+      for (i = 1; i <= P->m; i++)
+      {  len = 0;
+         for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  ind[++len] = toLit(aij->col->j-1);
+            if (aij->val < 0.0)
+               ind[len] = lit_neg(ind[len]);
+         }
+         xassert(len > 0);
+         xassert(solver_addclause(s, &ind[1], &ind[1+len]));
+      }
+      xfree(ind);
+      /* call the solver */
+      s->verbosity = 1;
+      if (solver_solve(s, 0, 0))
+      {  /* instance is reported as satisfiable */
+         P->mip_stat = GLP_OPT;
+         /* copy solution to the problem object */
+         xassert(s->model.size == P->n);
+         for (j = 1; j <= P->n; j++)
+         {  P->col[j]->mipx =
+               s->model.ptr[j-1] == l_True ? 1.0 : 0.0;
+         }
+         /* compute row values */
+         for (i = 1; i <= P->m; i++)
+         {  sum = 0;
+            for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+               sum += aij->val * aij->col->mipx;
+            P->row[i]->mipx = sum;
+         }
+         /* check integer feasibility */
+         for (i = 1; i <= P->m; i++)
+         {  if (P->row[i]->mipx < P->row[i]->lb)
+            {  /* solution is wrong */
+               P->mip_stat = GLP_UNDEF;
+               break;
+            }
+         }
+      }
+      else
+      {  /* instance is reported as unsatisfiable */
+         P->mip_stat = GLP_NOFEAS;
+      }
+      solver_delete(s);
+fini: /* report the instance status */
+      if (P->mip_stat == GLP_OPT)
+      {  xprintf("SATISFIABLE\n");
+         ret = 0;
+      }
+      else if (P->mip_stat == GLP_NOFEAS)
+      {  xprintf("UNSATISFIABLE\n");
+         ret = 0;
+      }
+      else
+      {  xprintf("glp_minisat1: solver failed\n");
+         ret = GLP_EFAIL;
+      }
+done: return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi20.c
===================================================================
--- deps/glpk/src/glpapi20.c	(revision 9)
+++ deps/glpk/src/glpapi20.c	(revision 9)
@@ -0,0 +1,256 @@
+/* glpapi20.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound)
+{     /* solve integer feasibility problem */
+      NPP *npp = NULL;
+      glp_prob *mip = NULL;
+      int *obj_ind = NULL;
+      double *obj_val = NULL;
+      int obj_row = 0;
+      int i, j, k, obj_len, temp, ret;
+      /* check the problem object */
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_intfeas1: P = %p; invalid problem object\n",
+            P);
+      if (P->tree != NULL)
+         xerror("glp_intfeas1: operation not allowed\n");
+      /* integer solution is currently undefined */
+      P->mip_stat = GLP_UNDEF;
+      P->mip_obj = 0.0;
+      /* check columns (variables) */
+      for (j = 1; j <= P->n; j++)
+      {  GLPCOL *col = P->col[j];
+#if 0 /* currently binarization is not yet implemented */
+         if (!(col->kind == GLP_IV || col->type == GLP_FX))
+         {  xprintf("glp_intfeas1: column %d: non-integer non-fixed var"
+               "iable not allowed\n", j);
+#else
+         if (!((col->kind == GLP_IV && col->lb == 0.0 && col->ub == 1.0)
+            || col->type == GLP_FX))
+         {  xprintf("glp_intfeas1: column %d: non-binary non-fixed vari"
+               "able not allowed\n", j);
+#endif
+            ret = GLP_EDATA;
+            goto done;
+         }
+         temp = (int)col->lb;
+         if ((double)temp != col->lb)
+         {  if (col->type == GLP_FX)
+               xprintf("glp_intfeas1: column %d: fixed value %g is non-"
+                  "integer or out of range\n", j, col->lb);
+            else
+               xprintf("glp_intfeas1: column %d: lower bound %g is non-"
+                  "integer or out of range\n", j, col->lb);
+            ret = GLP_EDATA;
+            goto done;
+         }
+         temp = (int)col->ub;
+         if ((double)temp != col->ub)
+         {  xprintf("glp_intfeas1: column %d: upper bound %g is non-int"
+               "eger or out of range\n", j, col->ub);
+            ret = GLP_EDATA;
+            goto done;
+         }
+         if (col->type == GLP_DB && col->lb > col->ub)
+         {  xprintf("glp_intfeas1: column %d: lower bound %g is greater"
+               " than upper bound %g\n", j, col->lb, col->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* check rows (constraints) */
+      for (i = 1; i <= P->m; i++)
+      {  GLPROW *row = P->row[i];
+         GLPAIJ *aij;
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  temp = (int)aij->val;
+            if ((double)temp != aij->val)
+            {  xprintf("glp_intfeas1: row = %d, column %d: constraint c"
+                  "oefficient %g is non-integer or out of range\n",
+                  i, aij->col->j, aij->val);
+               ret = GLP_EDATA;
+               goto done;
+            }
+         }
+         temp = (int)row->lb;
+         if ((double)temp != row->lb)
+         {  if (row->type == GLP_FX)
+               xprintf("glp_intfeas1: row = %d: fixed value %g is non-i"
+                  "nteger or out of range\n", i, row->lb);
+            else
+               xprintf("glp_intfeas1: row = %d: lower bound %g is non-i"
+                  "nteger or out of range\n", i, row->lb);
+            ret = GLP_EDATA;
+            goto done;
+         }
+         temp = (int)row->ub;
+         if ((double)temp != row->ub)
+         {  xprintf("glp_intfeas1: row = %d: upper bound %g is non-inte"
+               "ger or out of range\n", i, row->ub);
+            ret = GLP_EDATA;
+            goto done;
+         }
+         if (row->type == GLP_DB && row->lb > row->ub)
+         {  xprintf("glp_intfeas1: row %d: lower bound %g is greater th"
+               "an upper bound %g\n", i, row->lb, row->ub);
+            ret = GLP_EBOUND;
+            goto done;
+         }
+      }
+      /* check the objective function */
+      temp = (int)P->c0;
+      if ((double)temp != P->c0)
+      {  xprintf("glp_intfeas1: objective constant term %g is non-integ"
+            "er or out of range\n", P->c0);
+         ret = GLP_EDATA;
+         goto done;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  temp = (int)P->col[j]->coef;
+         if ((double)temp != P->col[j]->coef)
+         {  xprintf("glp_intfeas1: column %d: objective coefficient is "
+               "non-integer or out of range\n", j, P->col[j]->coef);
+            ret = GLP_EDATA;
+            goto done;
+         }
+      }
+      /* save the objective function and set it to zero */
+      obj_ind = xcalloc(1+P->n, sizeof(int));
+      obj_val = xcalloc(1+P->n, sizeof(double));
+      obj_len = 0;
+      obj_ind[0] = 0;
+      obj_val[0] = P->c0;
+      P->c0 = 0.0;
+      for (j = 1; j <= P->n; j++)
+      {  if (P->col[j]->coef != 0.0)
+         {  obj_len++;
+            obj_ind[obj_len] = j;
+            obj_val[obj_len] = P->col[j]->coef;
+            P->col[j]->coef = 0.0;
+         }
+      }
+      /* add inequality to bound the objective function, if required */
+      if (!use_bound)
+         xprintf("Will search for ANY feasible solution\n");
+      else
+      {  xprintf("Will search only for solution not worse than %d\n",
+            obj_bound);
+         obj_row = glp_add_rows(P, 1);
+         glp_set_mat_row(P, obj_row, obj_len, obj_ind, obj_val);
+         if (P->dir == GLP_MIN)
+            glp_set_row_bnds(P, obj_row,
+               GLP_UP, 0.0, (double)obj_bound - obj_val[0]);
+         else if (P->dir == GLP_MAX)
+            glp_set_row_bnds(P, obj_row,
+               GLP_LO, (double)obj_bound - obj_val[0], 0.0);
+         else
+            xassert(P != P);
+      }
+      /* create preprocessor workspace */
+      xprintf("Translating to CNF-SAT...\n");
+      xprintf("Original problem has %d row%s, %d column%s, and %d non-z"
+         "ero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" :
+         "s", P->nnz, P->nnz == 1 ? "" : "s");
+      npp = npp_create_wksp();
+      /* load the original problem into the preprocessor workspace */
+      npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
+      /* perform translation to SAT-CNF problem instance */
+      ret = npp_sat_encode_prob(npp);
+      if (ret == 0)
+         ;
+      else if (ret == GLP_ENOPFS)
+         xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
+      else if (ret == GLP_ERANGE)
+         xprintf("glp_intfeas1: translation to SAT-CNF failed because o"
+            "f integer overflow\n");
+      else
+         xassert(ret != ret);
+      if (ret != 0)
+         goto done;
+      /* build SAT-CNF problem instance and try to solve it */
+      mip = glp_create_prob();
+      npp_build_prob(npp, mip);
+      ret = glp_minisat1(mip);
+      /* only integer feasible solution can be postprocessed */
+      if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
+      {  P->mip_stat = mip->mip_stat;
+         goto done;
+      }
+      /* postprocess the solution found */
+      npp_postprocess(npp, mip);
+      /* the transformed problem is no longer needed */
+      glp_delete_prob(mip), mip = NULL;
+      /* store solution to the original problem object */
+      npp_unload_sol(npp, P);
+      /* change the solution status to 'integer feasible' */
+      P->mip_stat = GLP_FEAS;
+      /* check integer feasibility */
+      for (i = 1; i <= P->m; i++)
+      {  GLPROW *row;
+         GLPAIJ *aij;
+         double sum;
+         row = P->row[i];
+         sum = 0.0;
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            sum += aij->val * aij->col->mipx;
+         xassert(sum == row->mipx);
+         if (row->type == GLP_LO || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xassert(sum >= row->lb);
+         if (row->type == GLP_UP || row->type == GLP_DB ||
+             row->type == GLP_FX)
+            xassert(sum <= row->ub);
+      }
+      /* compute value of the original objective function */
+      P->mip_obj = obj_val[0];
+      for (k = 1; k <= obj_len; k++)
+         P->mip_obj += obj_val[k] * P->col[obj_ind[k]]->mipx;
+      xprintf("Objective value = %17.9e\n", P->mip_obj);
+done: /* delete the transformed problem, if it exists */
+      if (mip != NULL)
+         glp_delete_prob(mip);
+      /* delete the preprocessor workspace, if it exists */
+      if (npp != NULL)
+         npp_delete_wksp(npp);
+      /* remove inequality used to bound the objective function */
+      if (obj_row > 0)
+      {  int ind[1+1];
+         ind[1] = obj_row;
+         glp_del_rows(P, 1, ind);
+      }
+      /* restore the original objective function */
+      if (obj_ind != NULL)
+      {  P->c0 = obj_val[0];
+         for (k = 1; k <= obj_len; k++)
+            P->col[obj_ind[k]]->coef = obj_val[k];
+         xfree(obj_ind);
+         xfree(obj_val);
+      }
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpapi21.c
===================================================================
--- deps/glpk/src/glpapi21.c	(revision 9)
+++ deps/glpk/src/glpapi21.c	(revision 9)
@@ -0,0 +1,1324 @@
+/* glpapi21.c (stand-alone LP/MIP solver) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpgmp.h"
+
+struct csa
+{     /* common storage area */
+      glp_prob *prob;
+      /* LP/MIP problem object */
+      glp_bfcp bfcp;
+      /* basis factorization control parameters */
+      glp_smcp smcp;
+      /* simplex method control parameters */
+      glp_iptcp iptcp;
+      /* interior-point method control parameters */
+      glp_iocp iocp;
+      /* integer optimizer control parameters */
+      glp_tran *tran;
+      /* model translator workspace */
+      glp_graph *graph;
+      /* network problem object */
+      int format;
+      /* problem file format: */
+#define FMT_MPS_DECK    1  /* fixed MPS */
+#define FMT_MPS_FILE    2  /* free MPS */
+#define FMT_LP          3  /* CPLEX LP */
+#define FMT_GLP         4  /* GLPK LP/MIP */
+#define FMT_MATHPROG    5  /* MathProg */
+#define FMT_MIN_COST    6  /* DIMACS min-cost flow */
+#define FMT_MAX_FLOW    7  /* DIMACS maximum flow */
+#if 1 /* 06/VIII-2011 */
+#define FMT_CNF         8  /* DIMACS CNF-SAT */
+#endif
+      const char *in_file;
+      /* name of input problem file */
+#define DATA_MAX 10
+      /* maximal number of input data files */
+      int ndf;
+      /* number of input data files specified */
+      const char *in_data[1+DATA_MAX];
+      /* name(s) of input data file(s) */
+      const char *out_dpy;
+      /* name of output file to send display output; NULL means the
+         display output is sent to the terminal */
+      int seed;
+      /* seed value to be passed to the MathProg translator; initially
+         set to 1; 0x80000000 means the value is omitted */
+      int solution;
+      /* solution type flag: */
+#define SOL_BASIC       1  /* basic */
+#define SOL_INTERIOR    2  /* interior-point */
+#define SOL_INTEGER     3  /* mixed integer */
+      const char *in_res;
+      /* name of input solution file in raw format */
+      int dir;
+      /* optimization direction flag:
+         0       - not specified
+         GLP_MIN - minimization
+         GLP_MAX - maximization */
+      int scale;
+      /* automatic problem scaling flag */
+      const char *out_sol;
+      /* name of output solution file in printable format */
+      const char *out_res;
+      /* name of output solution file in raw format */
+      const char *out_ranges;
+      /* name of output file to write sensitivity analysis report */
+      int check;
+      /* input data checking flag; no solution is performed */
+      const char *new_name;
+      /* new name to be assigned to the problem */
+      const char *out_mps;
+      /* name of output problem file in fixed MPS format */
+      const char *out_freemps;
+      /* name of output problem file in free MPS format */
+      const char *out_cpxlp;
+      /* name of output problem file in CPLEX LP format */
+      const char *out_glp;
+      /* name of output problem file in GLPK format */
+      const char *out_pb;
+      /* name of output problem file in OPB format */
+      const char *out_npb;
+      /* name of output problem file in normalized OPB format */
+#if 1 /* 06/VIII-2011 */
+      const char *out_cnf;
+      /* name of output problem file in DIMACS CNF-SAT format */
+#endif
+      const char *log_file;
+      /* name of output file to hardcopy terminal output */
+      int crash;
+      /* initial basis option: */
+#define USE_STD_BASIS   1  /* use standard basis */
+#define USE_ADV_BASIS   2  /* use advanced basis */
+#define USE_CPX_BASIS   3  /* use Bixby's basis */
+#define USE_INI_BASIS   4  /* use initial basis from ini_file */
+      const char *ini_file;
+      /* name of input file containing initial basis */
+      int exact;
+      /* flag to use glp_exact rather than glp_simplex */
+      int xcheck;
+      /* flag to check final basis with glp_exact */
+      int nomip;
+      /* flag to consider MIP as pure LP */
+#if 1 /* 15/VIII-2011 */
+      int minisat;
+      /* option to solve feasibility problem with MiniSat solver */
+      int use_bnd;
+      /* option to bound objective function */
+      int obj_bnd;
+      /* upper (minization) or lower (maximization) objective bound */
+#endif
+};
+
+static void print_help(const char *my_name)
+{     /* print help information */
+      xprintf("Usage: %s [options...] filename\n", my_name);
+      xprintf("\n");
+      xprintf("General options:\n");
+      xprintf("   --mps             read LP/MIP problem in fixed MPS fo"
+         "rmat\n");
+      xprintf("   --freemps         read LP/MIP problem in free MPS for"
+         "mat (default)\n");
+      xprintf("   --lp              read LP/MIP problem in CPLEX LP for"
+         "mat\n");
+      xprintf("   --glp             read LP/MIP problem in GLPK format "
+         "\n");
+      xprintf("   --math            read LP/MIP model written in GNU Ma"
+         "thProg modeling\n");
+      xprintf("                     language\n");
+      xprintf("   -m filename, --model filename\n");
+      xprintf("                     read model section and optional dat"
+         "a section from\n");
+      xprintf("                     filename (same as --math)\n");
+      xprintf("   -d filename, --data filename\n");
+      xprintf("                     read data section from filename (fo"
+         "r --math only);\n");
+      xprintf("                     if model file also has data section"
+         ", it is ignored\n");
+      xprintf("   -y filename, --display filename\n");
+      xprintf("                     send display output to filename (fo"
+         "r --math only);\n");
+      xprintf("                     by default the output is sent to te"
+         "rminal\n");
+      xprintf("   --seed value      initialize pseudo-random number gen"
+         "erator used in\n");
+      xprintf("                     MathProg model with specified seed "
+         "(any integer);\n");
+      xprintf("                     if seed value is ?, some random see"
+         "d will be used\n");
+      xprintf("   --mincost         read min-cost flow problem in DIMAC"
+         "S format\n");
+      xprintf("   --maxflow         read maximum flow problem in DIMACS"
+         " format\n");
+#if 1 /* 06/VIII-2011 */
+      xprintf("   --cnf             read CNF-SAT problem in DIMACS form"
+         "at\n");
+#endif
+      xprintf("   --simplex         use simplex method (default)\n");
+      xprintf("   --interior        use interior point method (LP only)"
+         "\n");
+      xprintf("   -r filename, --read filename\n");
+      xprintf("                     read solution from filename rather "
+         "to find it with\n");
+      xprintf("                     the solver\n");
+      xprintf("   --min             minimization\n");
+      xprintf("   --max             maximization\n");
+      xprintf("   --scale           scale problem (default)\n");
+      xprintf("   --noscale         do not scale problem\n");
+      xprintf("   -o filename, --output filename\n");
+      xprintf("                     write solution to filename in print"
+         "able format\n");
+      xprintf("   -w filename, --write filename\n");
+      xprintf("                     write solution to filename in plain"
+         " text format\n");
+      xprintf("   --ranges filename\n");
+      xprintf("                     write sensitivity analysis report t"
+         "o filename in\n");
+      xprintf("                     printable format (simplex only)\n");
+      xprintf("   --tmlim nnn       limit solution time to nnn seconds "
+         "\n");
+      xprintf("   --memlim nnn      limit available memory to nnn megab"
+         "ytes\n");
+      xprintf("   --check           do not solve problem, check input d"
+         "ata only\n");
+      xprintf("   --name probname   change problem name to probname\n");
+      xprintf("   --wmps filename   write problem to filename in fixed "
+         "MPS format\n");
+      xprintf("   --wfreemps filename\n");
+      xprintf("                     write problem to filename in free M"
+         "PS format\n");
+      xprintf("   --wlp filename    write problem to filename in CPLEX "
+         "LP format\n");
+      xprintf("   --wglp filename   write problem to filename in GLPK f"
+         "ormat\n");
+#if 0
+      xprintf("   --wpb filename    write problem to filename in OPB fo"
+         "rmat\n");
+      xprintf("   --wnpb filename   write problem to filename in normal"
+         "ized OPB format\n");
+#endif
+#if 1 /* 06/VIII-2011 */
+      xprintf("   --wcnf filename   write problem to filename in DIMACS"
+         " CNF-SAT format\n");
+#endif
+      xprintf("   --log filename    write copy of terminal output to fi"
+         "lename\n");
+      xprintf("   -h, --help        display this help information and e"
+         "xit\n");
+      xprintf("   -v, --version     display program version and exit\n")
+         ;
+      xprintf("\n");
+      xprintf("LP basis factorization options:\n");
+      xprintf("   --luf             LU + Forrest-Tomlin update\n");
+      xprintf("                     (faster, less stable; default)\n");
+      xprintf("   --cbg             LU + Schur complement + Bartels-Gol"
+         "ub update\n");
+      xprintf("                     (slower, more stable)\n");
+      xprintf("   --cgr             LU + Schur complement + Givens rota"
+         "tion update\n");
+      xprintf("                     (slower, more stable)\n");
+      xprintf("\n");
+      xprintf("Options specific to simplex solver:\n");
+      xprintf("   --primal          use primal simplex (default)\n");
+      xprintf("   --dual            use dual simplex\n");
+      xprintf("   --std             use standard initial basis of all s"
+         "lacks\n");
+      xprintf("   --adv             use advanced initial basis (default"
+         ")\n");
+      xprintf("   --bib             use Bixby's initial basis\n");
+      xprintf("   --ini filename    use as initial basis previously sav"
+         "ed with -w\n");
+      xprintf("                     (disables LP presolver)\n");
+      xprintf("   --steep           use steepest edge technique (defaul"
+         "t)\n");
+      xprintf("   --nosteep         use standard \"textbook\" pricing\n"
+         );
+      xprintf("   --relax           use Harris' two-pass ratio test (de"
+         "fault)\n");
+      xprintf("   --norelax         use standard \"textbook\" ratio tes"
+         "t\n");
+      xprintf("   --presol          use presolver (default; assumes --s"
+         "cale and --adv)\n");
+      xprintf("   --nopresol        do not use presolver\n");
+      xprintf("   --exact           use simplex method based on exact a"
+         "rithmetic\n");
+      xprintf("   --xcheck          check final basis using exact arith"
+         "metic\n");
+      xprintf("\n");
+      xprintf("Options specific to interior-point solver:\n");
+      xprintf("   --nord            use natural (original) ordering\n");
+      xprintf("   --qmd             use quotient minimum degree orderin"
+         "g\n");
+      xprintf("   --amd             use approximate minimum degree orde"
+         "ring (default)\n");
+      xprintf("   --symamd          use approximate minimum degree orde"
+         "ring\n");
+      xprintf("\n");
+      xprintf("Options specific to MIP solver:\n");
+      xprintf("   --nomip           consider all integer variables as c"
+         "ontinuous\n");
+      xprintf("                     (allows solving MIP as pure LP)\n");
+      xprintf("   --first           branch on first integer variable\n")
+         ;
+      xprintf("   --last            branch on last integer variable\n");
+      xprintf("   --mostf           branch on most fractional variable "
+         "\n");
+      xprintf("   --drtom           branch using heuristic by Driebeck "
+         "and Tomlin\n");
+      xprintf("                     (default)\n");
+      xprintf("   --pcost           branch using hybrid pseudocost heur"
+         "istic (may be\n");
+      xprintf("                     useful for hard instances)\n");
+      xprintf("   --dfs             backtrack using depth first search "
+         "\n");
+      xprintf("   --bfs             backtrack using breadth first searc"
+         "h\n");
+      xprintf("   --bestp           backtrack using the best projection"
+         " heuristic\n");
+      xprintf("   --bestb           backtrack using node with best loca"
+         "l bound\n");
+      xprintf("                     (default)\n");
+      xprintf("   --intopt          use MIP presolver (default)\n");
+      xprintf("   --nointopt        do not use MIP presolver\n");
+      xprintf("   --binarize        replace general integer variables b"
+         "y binary ones\n");
+      xprintf("                     (assumes --intopt)\n");
+      xprintf("   --fpump           apply feasibility pump heuristic\n")
+         ;
+      xprintf("   --gomory          generate Gomory's mixed integer cut"
+         "s\n");
+      xprintf("   --mir             generate MIR (mixed integer roundin"
+         "g) cuts\n");
+      xprintf("   --cover           generate mixed cover cuts\n");
+      xprintf("   --clique          generate clique cuts\n");
+      xprintf("   --cuts            generate all cuts above\n");
+      xprintf("   --mipgap tol      set relative mip gap tolerance to t"
+         "ol\n");
+#if 1 /* 15/VIII-2011 */
+      xprintf("   --minisat         translate integer feasibility probl"
+         "em to CNF-SAT\n");
+      xprintf("                     and solve it with MiniSat solver\n")
+         ;
+      xprintf("   --objbnd bound    add inequality obj <= bound (minimi"
+         "zation) or\n");
+      xprintf("                     obj >= bound (maximization) to inte"
+         "ger feasibility\n");
+      xprintf("                     problem (assumes --minisat)\n");
+#endif
+      xprintf("\n");
+      xprintf("For description of the MPS and CPLEX LP formats see Refe"
+         "rence Manual.\n");
+      xprintf("For description of the modeling language see \"GLPK: Mod"
+         "eling Language\n");
+      xprintf("GNU MathProg\". Both documents are included in the GLPK "
+         "distribution.\n");
+      xprintf("\n");
+      xprintf("See GLPK web page at <http://www.gnu.org/software/glpk/g"
+         "lpk.html>.\n");
+      xprintf("\n");
+      xprintf("Please report bugs to <bug-glpk@gnu.org>.\n");
+      return;
+}
+
+static void print_version(int briefly)
+{     /* print version information */
+      xprintf("GLPSOL: GLPK LP/MIP Solver, v%s\n", glp_version());
+      if (briefly) goto done;
+      xprintf("\n");
+      xprintf("Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, "
+         "2007, 2008,\n");
+      xprintf("2009, 2010, 2011 Andrew Makhorin, Department for Applied"
+         " Informatics,\n");
+      xprintf("Moscow Aviation Institute, Moscow, Russia. All rights re"
+         "served.\n");
+      xprintf("\n");
+      xprintf("This program has ABSOLUTELY NO WARRANTY.\n");
+      xprintf("\n");
+      xprintf("This program is free software; you may re-distribute it "
+         "under the terms\n");
+      xprintf("of the GNU General Public License version 3 or later.\n")
+         ;
+done: return;
+}
+
+static int parse_cmdline(struct csa *csa, int argc, const char *argv[])
+{     /* parse command-line parameters */
+      int k;
+#define p(str) (strcmp(argv[k], str) == 0)
+      for (k = 1; k < argc; k++)
+      {  if (p("--mps"))
+            csa->format = FMT_MPS_DECK;
+         else if (p("--freemps"))
+            csa->format = FMT_MPS_FILE;
+         else if (p("--lp") || p("--cpxlp"))
+            csa->format = FMT_LP;
+         else if (p("--glp"))
+            csa->format = FMT_GLP;
+         else if (p("--math") || p("-m") || p("--model"))
+            csa->format = FMT_MATHPROG;
+         else if (p("-d") || p("--data"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No input data file specified\n");
+               return 1;
+            }
+            if (csa->ndf == DATA_MAX)
+            {  xprintf("Too many input data files\n");
+               return 1;
+            }
+            csa->in_data[++(csa->ndf)] = argv[k];
+         }
+         else if (p("-y") || p("--display"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No display output file specified\n");
+               return 1;
+            }
+            if (csa->out_dpy != NULL)
+            {  xprintf("Only one display output file allowed\n");
+               return 1;
+            }
+            csa->out_dpy = argv[k];
+         }
+         else if (p("--seed"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' ||
+               argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
+            {  xprintf("No seed value specified\n");
+               return 1;
+            }
+            if (strcmp(argv[k], "?") == 0)
+               csa->seed = 0x80000000;
+            else if (str2int(argv[k], &csa->seed))
+            {  xprintf("Invalid seed value `%s'\n", argv[k]);
+               return 1;
+            }
+         }
+         else if (p("--mincost"))
+            csa->format = FMT_MIN_COST;
+         else if (p("--maxflow"))
+            csa->format = FMT_MAX_FLOW;
+#if 1 /* 06/VIII-2011 */
+         else if (p("--cnf"))
+            csa->format = FMT_CNF;
+#endif
+         else if (p("--simplex"))
+            csa->solution = SOL_BASIC;
+         else if (p("--interior"))
+            csa->solution = SOL_INTERIOR;
+#if 1 /* 28/V-2010 */
+         else if (p("--alien"))
+            csa->iocp.alien = GLP_ON;
+#endif
+         else if (p("-r") || p("--read"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No input solution file specified\n");
+               return 1;
+            }
+            if (csa->in_res != NULL)
+            {  xprintf("Only one input solution file allowed\n");
+               return 1;
+            }
+            csa->in_res = argv[k];
+         }
+         else if (p("--min"))
+            csa->dir = GLP_MIN;
+         else if (p("--max"))
+            csa->dir = GLP_MAX;
+         else if (p("--scale"))
+            csa->scale = 1;
+         else if (p("--noscale"))
+            csa->scale = 0;
+         else if (p("-o") || p("--output"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No output solution file specified\n");
+               return 1;
+            }
+            if (csa->out_sol != NULL)
+            {  xprintf("Only one output solution file allowed\n");
+               return 1;
+            }
+            csa->out_sol = argv[k];
+         }
+         else if (p("-w") || p("--write"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No output solution file specified\n");
+               return 1;
+            }
+            if (csa->out_res != NULL)
+            {  xprintf("Only one output solution file allowed\n");
+               return 1;
+            }
+            csa->out_res = argv[k];
+         }
+         else if (p("--ranges") || p("--bounds"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No output file specified to write sensitivity a"
+                  "nalysis report\n");
+               return 1;
+            }
+            if (csa->out_ranges != NULL)
+            {  xprintf("Only one output file allowed to write sensitivi"
+                  "ty analysis report\n");
+               return 1;
+            }
+            csa->out_ranges = argv[k];
+         }
+         else if (p("--tmlim"))
+         {  int tm_lim;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No time limit specified\n");
+               return 1;
+            }
+            if (str2int(argv[k], &tm_lim) || tm_lim < 0)
+            {  xprintf("Invalid time limit `%s'\n", argv[k]);
+               return 1;
+            }
+            if (tm_lim <= INT_MAX / 1000)
+               csa->smcp.tm_lim = csa->iocp.tm_lim = 1000 * tm_lim;
+            else
+               csa->smcp.tm_lim = csa->iocp.tm_lim = INT_MAX;
+         }
+         else if (p("--memlim"))
+         {  int mem_lim;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No memory limit specified\n");
+               return 1;
+            }
+            if (str2int(argv[k], &mem_lim) || mem_lim < 1)
+            {  xprintf("Invalid memory limit `%s'\n", argv[k]);
+               return 1;
+            }
+            glp_mem_limit(mem_lim);
+         }
+         else if (p("--check"))
+            csa->check = 1;
+         else if (p("--name"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No problem name specified\n");
+               return 1;
+            }
+            if (csa->new_name != NULL)
+            {  xprintf("Only one problem name allowed\n");
+               return 1;
+            }
+            csa->new_name = argv[k];
+         }
+         else if (p("--wmps"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No fixed MPS output file specified\n");
+               return 1;
+            }
+            if (csa->out_mps != NULL)
+            {  xprintf("Only one fixed MPS output file allowed\n");
+               return 1;
+            }
+            csa->out_mps = argv[k];
+         }
+         else if (p("--wfreemps"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No free MPS output file specified\n");
+               return 1;
+            }
+            if (csa->out_freemps != NULL)
+            {  xprintf("Only one free MPS output file allowed\n");
+               return 1;
+            }
+            csa->out_freemps = argv[k];
+         }
+         else if (p("--wlp") || p("--wcpxlp") || p("--wlpt"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No CPLEX LP output file specified\n");
+               return 1;
+            }
+            if (csa->out_cpxlp != NULL)
+            {  xprintf("Only one CPLEX LP output file allowed\n");
+               return 1;
+            }
+            csa->out_cpxlp = argv[k];
+         }
+         else if (p("--wglp"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No GLPK LP/MIP output file specified\n");
+               return 1;
+            }
+            if (csa->out_glp != NULL)
+            {  xprintf("Only one GLPK LP/MIP output file allowed\n");
+               return 1;
+            }
+            csa->out_glp = argv[k];
+         }
+         else if (p("--wpb"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No problem output file specified\n");
+               return 1;
+            }
+            if (csa->out_pb != NULL)
+            {  xprintf("Only one OPB output file allowed\n");
+               return 1;
+            }
+            csa->out_pb = argv[k];
+         }
+         else if (p("--wnpb"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No problem output file specified\n");
+               return 1;
+            }
+            if (csa->out_npb != NULL)
+            {  xprintf("Only one normalized OPB output file allowed\n");
+               return 1;
+            }
+            csa->out_npb = argv[k];
+         }
+#if 1 /* 06/VIII-2011 */
+         else if (p("--wcnf"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No problem output file specified\n");
+               return 1;
+            }
+            if (csa->out_cnf != NULL)
+            {  xprintf("Only one output DIMACS CNF-SAT file allowed\n");
+               return 1;
+            }
+            csa->out_cnf = argv[k];
+         }
+#endif
+         else if (p("--log"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No log file specified\n");
+               return 1;
+            }
+            if (csa->log_file != NULL)
+            {  xprintf("Only one log file allowed\n");
+               return 1;
+            }
+            csa->log_file = argv[k];
+         }
+         else if (p("-h") || p("--help"))
+         {  print_help(argv[0]);
+            return -1;
+         }
+         else if (p("-v") || p("--version"))
+         {  print_version(0);
+            return -1;
+         }
+         else if (p("--luf"))
+            csa->bfcp.type = GLP_BF_FT;
+         else if (p("--cbg"))
+            csa->bfcp.type = GLP_BF_BG;
+         else if (p("--cgr"))
+            csa->bfcp.type = GLP_BF_GR;
+         else if (p("--primal"))
+            csa->smcp.meth = GLP_PRIMAL;
+         else if (p("--dual"))
+            csa->smcp.meth = GLP_DUAL;
+         else if (p("--std"))
+            csa->crash = USE_STD_BASIS;
+         else if (p("--adv"))
+            csa->crash = USE_ADV_BASIS;
+         else if (p("--bib"))
+            csa->crash = USE_CPX_BASIS;
+         else if (p("--ini"))
+         {  csa->crash = USE_INI_BASIS;
+            csa->smcp.presolve = GLP_OFF;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No initial basis file specified\n");
+               return 1;
+            }
+            if (csa->ini_file != NULL)
+            {  xprintf("Only one initial basis file allowed\n");
+               return 1;
+            }
+            csa->ini_file = argv[k];
+         }
+         else if (p("--steep"))
+            csa->smcp.pricing = GLP_PT_PSE;
+         else if (p("--nosteep"))
+            csa->smcp.pricing = GLP_PT_STD;
+         else if (p("--relax"))
+            csa->smcp.r_test = GLP_RT_HAR;
+         else if (p("--norelax"))
+            csa->smcp.r_test = GLP_RT_STD;
+         else if (p("--presol"))
+            csa->smcp.presolve = GLP_ON;
+         else if (p("--nopresol"))
+            csa->smcp.presolve = GLP_OFF;
+         else if (p("--exact"))
+            csa->exact = 1;
+         else if (p("--xcheck"))
+            csa->xcheck = 1;
+         else if (p("--nord"))
+            csa->iptcp.ord_alg = GLP_ORD_NONE;
+         else if (p("--qmd"))
+            csa->iptcp.ord_alg = GLP_ORD_QMD;
+         else if (p("--amd"))
+            csa->iptcp.ord_alg = GLP_ORD_AMD;
+         else if (p("--symamd"))
+            csa->iptcp.ord_alg = GLP_ORD_SYMAMD;
+         else if (p("--nomip"))
+            csa->nomip = 1;
+         else if (p("--first"))
+            csa->iocp.br_tech = GLP_BR_FFV;
+         else if (p("--last"))
+            csa->iocp.br_tech = GLP_BR_LFV;
+         else if (p("--drtom"))
+            csa->iocp.br_tech = GLP_BR_DTH;
+         else if (p("--mostf"))
+            csa->iocp.br_tech = GLP_BR_MFV;
+         else if (p("--pcost"))
+            csa->iocp.br_tech = GLP_BR_PCH;
+         else if (p("--dfs"))
+            csa->iocp.bt_tech = GLP_BT_DFS;
+         else if (p("--bfs"))
+            csa->iocp.bt_tech = GLP_BT_BFS;
+         else if (p("--bestp"))
+            csa->iocp.bt_tech = GLP_BT_BPH;
+         else if (p("--bestb"))
+            csa->iocp.bt_tech = GLP_BT_BLB;
+         else if (p("--intopt"))
+            csa->iocp.presolve = GLP_ON;
+         else if (p("--nointopt"))
+            csa->iocp.presolve = GLP_OFF;
+         else if (p("--binarize"))
+            csa->iocp.presolve = csa->iocp.binarize = GLP_ON;
+         else if (p("--fpump"))
+            csa->iocp.fp_heur = GLP_ON;
+         else if (p("--gomory"))
+            csa->iocp.gmi_cuts = GLP_ON;
+         else if (p("--mir"))
+            csa->iocp.mir_cuts = GLP_ON;
+         else if (p("--cover"))
+            csa->iocp.cov_cuts = GLP_ON;
+         else if (p("--clique"))
+            csa->iocp.clq_cuts = GLP_ON;
+         else if (p("--cuts"))
+            csa->iocp.gmi_cuts = csa->iocp.mir_cuts =
+            csa->iocp.cov_cuts = csa->iocp.clq_cuts = GLP_ON;
+         else if (p("--mipgap"))
+         {  double mip_gap;
+            k++;
+            if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-')
+            {  xprintf("No relative gap tolerance specified\n");
+               return 1;
+            }
+            if (str2num(argv[k], &mip_gap) || mip_gap < 0.0)
+            {  xprintf("Invalid relative mip gap tolerance `%s'\n",
+                  argv[k]);
+               return 1;
+            }
+            csa->iocp.mip_gap = mip_gap;
+         }
+#if 1 /* 15/VIII-2011 */
+         else if (p("--minisat"))
+            csa->minisat = 1;
+         else if (p("--objbnd"))
+         {  k++;
+            if (k == argc || argv[k][0] == '\0' ||
+               argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1]))
+            {  xprintf("No objective bound specified\n");
+               return 1;
+            }
+            csa->minisat = 1;
+            csa->use_bnd = 1;
+            if (str2int(argv[k], &csa->obj_bnd))
+            {  xprintf("Invalid objective bound `%s' (should be integer"
+                  " value)\n", argv[k]);
+               return 1;
+            }
+         }
+#endif
+         else if (argv[k][0] == '-' ||
+                 (argv[k][0] == '-' && argv[k][1] == '-'))
+         {  xprintf("Invalid option `%s'; try %s --help\n",
+               argv[k], argv[0]);
+            return 1;
+         }
+         else
+         {  if (csa->in_file != NULL)
+            {  xprintf("Only one input problem file allowed\n");
+               return 1;
+            }
+            csa->in_file = argv[k];
+         }
+      }
+#undef p
+      return 0;
+}
+
+typedef struct { double rhs, pi; } v_data;
+typedef struct { double low, cap, cost, x; } a_data;
+
+int glp_main(int argc, const char *argv[])
+{     /* stand-alone LP/MIP solver */
+      struct csa _csa, *csa = &_csa;
+      int ret;
+      glp_long start;
+      /* perform initialization */
+      csa->prob = glp_create_prob();
+      glp_get_bfcp(csa->prob, &csa->bfcp);
+      glp_init_smcp(&csa->smcp);
+      csa->smcp.presolve = GLP_ON;
+      glp_init_iptcp(&csa->iptcp);
+      glp_init_iocp(&csa->iocp);
+      csa->iocp.presolve = GLP_ON;
+      csa->tran = NULL;
+      csa->graph = NULL;
+      csa->format = FMT_MPS_FILE;
+      csa->in_file = NULL;
+      csa->ndf = 0;
+      csa->out_dpy = NULL;
+      csa->seed = 1;
+      csa->solution = SOL_BASIC;
+      csa->in_res = NULL;
+      csa->dir = 0;
+      csa->scale = 1;
+      csa->out_sol = NULL;
+      csa->out_res = NULL;
+      csa->out_ranges = NULL;
+      csa->check = 0;
+      csa->new_name = NULL;
+      csa->out_mps = NULL;
+      csa->out_freemps = NULL;
+      csa->out_cpxlp = NULL;
+      csa->out_glp = NULL;
+      csa->out_pb = NULL;
+      csa->out_npb = NULL;
+#if 1 /* 06/VIII-2011 */
+      csa->out_cnf = NULL;
+#endif
+      csa->log_file = NULL;
+      csa->crash = USE_ADV_BASIS;
+      csa->ini_file = NULL;
+      csa->exact = 0;
+      csa->xcheck = 0;
+      csa->nomip = 0;
+#if 1 /* 15/VIII-2011 */
+      csa->minisat = 0;
+      csa->use_bnd = 0;
+      csa->obj_bnd = 0;
+#endif
+      /* parse command-line parameters */
+      ret = parse_cmdline(csa, argc, argv);
+      if (ret < 0)
+      {  ret = EXIT_SUCCESS;
+         goto done;
+      }
+      if (ret > 0)
+      {  ret = EXIT_FAILURE;
+         goto done;
+      }
+      /*--------------------------------------------------------------*/
+      /* remove all output files specified in the command line */
+      if (csa->out_dpy != NULL) remove(csa->out_dpy);
+      if (csa->out_sol != NULL) remove(csa->out_sol);
+      if (csa->out_res != NULL) remove(csa->out_res);
+      if (csa->out_ranges != NULL) remove(csa->out_ranges);
+      if (csa->out_mps != NULL) remove(csa->out_mps);
+      if (csa->out_freemps != NULL) remove(csa->out_freemps);
+      if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp);
+      if (csa->out_glp != NULL) remove(csa->out_glp);
+      if (csa->out_pb != NULL) remove(csa->out_pb);
+      if (csa->out_npb != NULL) remove(csa->out_npb);
+#if 1 /* 06/VIII-2011 */
+      if (csa->out_cnf != NULL) remove(csa->out_cnf);
+#endif
+      if (csa->log_file != NULL) remove(csa->log_file);
+      /*--------------------------------------------------------------*/
+      /* open log file, if required */
+      if (csa->log_file != NULL)
+      {  if (glp_open_tee(csa->log_file))
+         {  xprintf("Unable to create log file\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /*--------------------------------------------------------------*/
+      /* print version information */
+      print_version(1);
+      /*--------------------------------------------------------------*/
+      /* print parameters specified in the command line */
+      if (argc > 1)
+      {  int k, len = INT_MAX;
+         xprintf("Parameter(s) specified in the command line:");
+         for (k = 1; k < argc; k++)
+         {  if (len > 72)
+               xprintf("\n"), len = 0;
+            xprintf(" %s", argv[k]);
+            len += 1 + strlen(argv[k]);
+         }
+         xprintf("\n");
+      }
+      /*--------------------------------------------------------------*/
+      /* read problem data from the input file */
+      if (csa->in_file == NULL)
+      {  xprintf("No input problem file specified; try %s --help\n",
+            argv[0]);
+         ret = EXIT_FAILURE;
+         goto done;
+      }
+      if (csa->format == FMT_MPS_DECK)
+      {  ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL,
+            csa->in_file);
+         if (ret != 0)
+err1:    {  xprintf("MPS file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      else if (csa->format == FMT_MPS_FILE)
+      {  ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL,
+            csa->in_file);
+         if (ret != 0) goto err1;
+      }
+      else if (csa->format == FMT_LP)
+      {  ret = glp_read_lp(csa->prob, NULL, csa->in_file);
+         if (ret != 0)
+         {  xprintf("CPLEX LP file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      else if (csa->format == FMT_GLP)
+      {  ret = glp_read_prob(csa->prob, 0, csa->in_file);
+         if (ret != 0)
+         {  xprintf("GLPK LP/MIP file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      else if (csa->format == FMT_MATHPROG)
+      {  int k;
+         /* allocate the translator workspace */
+         csa->tran = glp_mpl_alloc_wksp();
+         /* set seed value */
+         if (csa->seed == 0x80000000)
+         {  csa->seed = glp_time().lo;
+            xprintf("Seed value %d will be used\n", csa->seed);
+         }
+         _glp_mpl_init_rand(csa->tran, csa->seed);
+         /* read model section and optional data section */
+         if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0))
+err2:    {  xprintf("MathProg model processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         /* read optional data section(s), if necessary */
+         for (k = 1; k <= csa->ndf; k++)
+         {  if (glp_mpl_read_data(csa->tran, csa->in_data[k]))
+               goto err2;
+         }
+         /* generate the model */
+         if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2;
+         /* build the problem instance from the model */
+         glp_mpl_build_prob(csa->tran, csa->prob);
+      }
+      else if (csa->format == FMT_MIN_COST)
+      {  csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
+         ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs),
+            offsetof(a_data, low), offsetof(a_data, cap),
+            offsetof(a_data, cost), csa->in_file);
+         if (ret != 0)
+         {  xprintf("DIMACS file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         glp_mincost_lp(csa->prob, csa->graph, GLP_ON,
+            offsetof(v_data, rhs), offsetof(a_data, low),
+            offsetof(a_data, cap), offsetof(a_data, cost));
+         glp_set_prob_name(csa->prob, csa->in_file);
+      }
+      else if (csa->format == FMT_MAX_FLOW)
+      {  int s, t;
+         csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data));
+         ret = glp_read_maxflow(csa->graph, &s, &t,
+            offsetof(a_data, cap), csa->in_file);
+         if (ret != 0)
+         {  xprintf("DIMACS file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t,
+            offsetof(a_data, cap));
+         glp_set_prob_name(csa->prob, csa->in_file);
+      }
+#if 1 /* 06/VIII-2011 */
+      else if (csa->format == FMT_CNF)
+      {  ret = glp_read_cnfsat(csa->prob, csa->in_file);
+         if (ret != 0)
+         {  xprintf("DIMACS file processing error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         glp_set_prob_name(csa->prob, csa->in_file);
+      }
+#endif
+      else
+         xassert(csa != csa);
+      /*--------------------------------------------------------------*/
+      /* change problem name, if required */
+      if (csa->new_name != NULL)
+         glp_set_prob_name(csa->prob, csa->new_name);
+      /* change optimization direction, if required */
+      if (csa->dir != 0)
+         glp_set_obj_dir(csa->prob, csa->dir);
+      /* sort elements of the constraint matrix */
+      glp_sort_matrix(csa->prob);
+      /*--------------------------------------------------------------*/
+      /* write problem data in fixed MPS format, if required */
+      if (csa->out_mps != NULL)
+      {  ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL,
+            csa->out_mps);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in fixed MPS format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in free MPS format, if required */
+      if (csa->out_freemps != NULL)
+      {  ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL,
+            csa->out_freemps);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in free MPS format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in CPLEX LP format, if required */
+      if (csa->out_cpxlp != NULL)
+      {  ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in CPLEX LP format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in GLPK format, if required */
+      if (csa->out_glp != NULL)
+      {  ret = glp_write_prob(csa->prob, 0, csa->out_glp);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in GLPK format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in OPB format, if required */
+      if (csa->out_pb != NULL)
+      {  ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0);
+         if (ret != 0)
+         {  xprintf("Unable to write problem in OPB format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem data in normalized OPB format, if required */
+      if (csa->out_npb != NULL)
+      {  ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1);
+         if (ret != 0)
+         {  xprintf(
+               "Unable to write problem in normalized OPB format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+#if 1 /* 06/VIII-2011 */
+      /* write problem data in DIMACS CNF-SAT format, if required */
+      if (csa->out_cnf != NULL)
+      {  ret = glp_write_cnfsat(csa->prob, csa->out_cnf);
+         if (ret != 0)
+         {  xprintf(
+               "Unable to write problem in DIMACS CNF-SAT format\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+#endif
+      /*--------------------------------------------------------------*/
+      /* if only problem data check is required, skip computations */
+      if (csa->check)
+      {  ret = EXIT_SUCCESS;
+         goto done;
+      }
+      /*--------------------------------------------------------------*/
+      /* determine the solution type */
+      if (!csa->nomip &&
+          glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0)
+      {  if (csa->solution == SOL_INTERIOR)
+         {  xprintf("Interior-point method is not able to solve MIP pro"
+               "blem; use --simplex\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         csa->solution = SOL_INTEGER;
+      }
+      /*--------------------------------------------------------------*/
+      /* if solution is provided, read it and skip computations */
+      if (csa->in_res != NULL)
+      {  if (csa->solution == SOL_BASIC)
+            ret = glp_read_sol(csa->prob, csa->in_res);
+         else if (csa->solution == SOL_INTERIOR)
+            ret = glp_read_ipt(csa->prob, csa->in_res);
+         else if (csa->solution == SOL_INTEGER)
+            ret = glp_read_mip(csa->prob, csa->in_res);
+         else
+            xassert(csa != csa);
+         if (ret != 0)
+         {  xprintf("Unable to read problem solution\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+         goto skip;
+      }
+      /*--------------------------------------------------------------*/
+      /* scale the problem data, if required */
+      if (csa->scale)
+      {  if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
+             csa->solution == SOL_INTERIOR ||
+             csa->solution == SOL_INTEGER && !csa->iocp.presolve)
+            glp_scale_prob(csa->prob, GLP_SF_AUTO);
+      }
+      /*--------------------------------------------------------------*/
+      /* construct starting LP basis */
+      if (csa->solution == SOL_BASIC && !csa->smcp.presolve ||
+          csa->solution == SOL_INTEGER && !csa->iocp.presolve)
+      {  if (csa->crash == USE_STD_BASIS)
+            glp_std_basis(csa->prob);
+         else if (csa->crash == USE_ADV_BASIS)
+            glp_adv_basis(csa->prob, 0);
+         else if (csa->crash == USE_CPX_BASIS)
+            glp_cpx_basis(csa->prob);
+         else if (csa->crash == USE_INI_BASIS)
+         {  ret = glp_read_sol(csa->prob, csa->ini_file);
+            if (ret != 0)
+            {  xprintf("Unable to read initial basis\n");
+               ret = EXIT_FAILURE;
+               goto done;
+            }
+         }
+         else
+            xassert(csa != csa);
+      }
+      /*--------------------------------------------------------------*/
+      /* solve the problem */
+      start = xtime();
+      if (csa->solution == SOL_BASIC)
+      {  if (!csa->exact)
+         {  glp_set_bfcp(csa->prob, &csa->bfcp);
+            glp_simplex(csa->prob, &csa->smcp);
+            if (csa->xcheck)
+            {  if (csa->smcp.presolve &&
+                   glp_get_status(csa->prob) != GLP_OPT)
+                  xprintf("If you need to check final basis for non-opt"
+                     "imal solution, use --nopresol\n");
+               else
+                  glp_exact(csa->prob, &csa->smcp);
+            }
+            if (csa->out_sol != NULL || csa->out_res != NULL)
+            {  if (csa->smcp.presolve &&
+                   glp_get_status(csa->prob) != GLP_OPT)
+               xprintf("If you need actual output for non-optimal solut"
+                  "ion, use --nopresol\n");
+            }
+         }
+         else
+            glp_exact(csa->prob, &csa->smcp);
+      }
+      else if (csa->solution == SOL_INTERIOR)
+         glp_interior(csa->prob, &csa->iptcp);
+#if 1 /* 15/VIII-2011 */
+      else if (csa->solution == SOL_INTEGER && csa->minisat)
+      {  if (glp_check_cnfsat(csa->prob) == 0)
+            glp_minisat1(csa->prob);
+         else
+            glp_intfeas1(csa->prob, csa->use_bnd, csa->obj_bnd);
+      }
+#endif
+      else if (csa->solution == SOL_INTEGER)
+      {  if (!csa->iocp.presolve)
+         {  glp_set_bfcp(csa->prob, &csa->bfcp);
+            glp_simplex(csa->prob, &csa->smcp);
+         }
+#if 0
+         csa->iocp.msg_lev = GLP_MSG_DBG;
+         csa->iocp.pp_tech = GLP_PP_NONE;
+#endif
+         glp_intopt(csa->prob, &csa->iocp);
+      }
+      else
+         xassert(csa != csa);
+      /*--------------------------------------------------------------*/
+      /* display statistics */
+      xprintf("Time used:   %.1f secs\n", xdifftime(xtime(), start));
+      {  glp_long tpeak;
+         char buf[50];
+         glp_mem_usage(NULL, NULL, NULL, &tpeak);
+         xprintf("Memory used: %.1f Mb (%s bytes)\n",
+            xltod(tpeak) / 1048576.0, xltoa(tpeak, buf));
+      }
+      /*--------------------------------------------------------------*/
+skip: /* postsolve the model, if necessary */
+      if (csa->tran != NULL)
+      {  if (csa->solution == SOL_BASIC)
+         {  if (!(glp_get_status(csa->prob) == GLP_OPT ||
+                  glp_get_status(csa->prob) == GLP_FEAS))
+               ret = -1;
+            else
+               ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL);
+         }
+         else if (csa->solution == SOL_INTERIOR)
+         {  if (!(glp_ipt_status(csa->prob) == GLP_OPT ||
+                  glp_ipt_status(csa->prob) == GLP_FEAS))
+               ret = -1;
+            else
+               ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT);
+         }
+         else if (csa->solution == SOL_INTEGER)
+         {  if (!(glp_mip_status(csa->prob) == GLP_OPT ||
+                  glp_mip_status(csa->prob) == GLP_FEAS))
+               ret = -1;
+            else
+               ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP);
+         }
+         else
+            xassert(csa != csa);
+         if (ret > 0)
+         {  xprintf("Model postsolving error\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /*--------------------------------------------------------------*/
+      /* write problem solution in printable format, if required */
+      if (csa->out_sol != NULL)
+      {  if (csa->solution == SOL_BASIC)
+            ret = lpx_print_sol(csa->prob, csa->out_sol);
+         else if (csa->solution == SOL_INTERIOR)
+            ret = lpx_print_ips(csa->prob, csa->out_sol);
+         else if (csa->solution == SOL_INTEGER)
+            ret = lpx_print_mip(csa->prob, csa->out_sol);
+         else
+            xassert(csa != csa);
+         if (ret != 0)
+         {  xprintf("Unable to write problem solution\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write problem solution in printable format, if required */
+      if (csa->out_res != NULL)
+      {  if (csa->solution == SOL_BASIC)
+            ret = glp_write_sol(csa->prob, csa->out_res);
+         else if (csa->solution == SOL_INTERIOR)
+            ret = glp_write_ipt(csa->prob, csa->out_res);
+         else if (csa->solution == SOL_INTEGER)
+            ret = glp_write_mip(csa->prob, csa->out_res);
+         else
+            xassert(csa != csa);
+         if (ret != 0)
+         {  xprintf("Unable to write problem solution\n");
+            ret = EXIT_FAILURE;
+            goto done;
+         }
+      }
+      /* write sensitivity analysis report, if required */
+      if (csa->out_ranges != NULL)
+      {  if (csa->solution == SOL_BASIC)
+         {  if (glp_get_status(csa->prob) == GLP_OPT)
+            {  if (glp_bf_exists(csa->prob))
+ranges:        {  ret = glp_print_ranges(csa->prob, 0, NULL, 0,
+                     csa->out_ranges);
+                  if (ret != 0)
+                  {  xprintf("Unable to write sensitivity analysis repo"
+                        "rt\n");
+                     ret = EXIT_FAILURE;
+                     goto done;
+                  }
+               }
+               else
+               {  ret = glp_factorize(csa->prob);
+                  if (ret == 0) goto ranges;
+                  xprintf("Cannot produce sensitivity analysis report d"
+                     "ue to error in basis factorization (glp_factorize"
+                     " returned %d); try --nopresol\n", ret);
+               }
+            }
+            else
+               xprintf("Cannot produce sensitivity analysis report for "
+                  "non-optimal basic solution\n");
+         }
+         else
+            xprintf("Cannot produce sensitivity analysis report for int"
+               "erior-point or MIP solution\n");
+      }
+      /*--------------------------------------------------------------*/
+      /* all seems to be ok */
+      ret = EXIT_SUCCESS;
+      /*--------------------------------------------------------------*/
+done: /* delete the LP/MIP problem object */
+      if (csa->prob != NULL)
+         glp_delete_prob(csa->prob);
+      /* free the translator workspace, if necessary */
+      if (csa->tran != NULL)
+         glp_mpl_free_wksp(csa->tran);
+      /* delete the network problem object, if necessary */
+      if (csa->graph != NULL)
+         glp_delete_graph(csa->graph);
+      xassert(gmp_pool_count() == 0);
+      gmp_free_mem();
+      /* close log file, if necessary */
+      if (csa->log_file != NULL) glp_close_tee();
+      /* check that no memory blocks are still allocated */
+      {  int count;
+         glp_long total;
+         glp_mem_usage(&count, NULL, &total, NULL);
+         if (count != 0)
+            xerror("Error: %d memory block(s) were lost\n", count);
+         xassert(count == 0);
+         xassert(total.lo == 0 && total.hi == 0);
+      }
+      /* free the GLPK environment */
+      glp_free_env();
+      /* return to the control program */
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpavl.c
===================================================================
--- deps/glpk/src/glpavl.c	(revision 9)
+++ deps/glpk/src/glpavl.c	(revision 9)
@@ -0,0 +1,357 @@
+/* glpavl.c (binary search tree) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpavl.h"
+
+AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
+      const void *key2), void *info)
+{     /* create AVL tree */
+      AVL *tree;
+      tree = xmalloc(sizeof(AVL));
+      tree->pool = dmp_create_pool();
+      tree->root = NULL;
+      tree->fcmp = fcmp;
+      tree->info = info;
+      tree->size = 0;
+      tree->height = 0;
+      return tree;
+}
+
+int avl_strcmp(void *info, const void *key1, const void *key2)
+{     /* compare character string keys */
+      xassert(info == info);
+      return strcmp(key1, key2);
+}
+
+static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node);
+
+AVLNODE *avl_insert_node(AVL *tree, const void *key)
+{     /* insert new node into AVL tree */
+      AVLNODE *p, *q, *r;
+      short int flag;
+      /* find an appropriate point for insertion */
+      p = NULL; q = tree->root;
+      while (q != NULL)
+      {  p = q;
+         if (tree->fcmp(tree->info, key, p->key) <= 0)
+         {  flag = 0;
+            q = p->left;
+            p->rank++;
+         }
+         else
+         {  flag = 1;
+            q = p->right;
+         }
+      }
+      /* create new node and insert it into the tree */
+      r = dmp_get_atom(tree->pool, sizeof(AVLNODE));
+      r->key = key; r->type = 0; r->link = NULL;
+      r->rank = 1; r->up = p;
+      r->flag = (short int)(p == NULL ? 0 : flag);
+      r->bal = 0; r->left = NULL; r->right = NULL;
+      tree->size++;
+      if (p == NULL)
+         tree->root = r;
+      else
+         if (flag == 0) p->left = r; else p->right = r;
+      /* go upstairs to the root and correct all subtrees affected by
+         insertion */
+      while (p != NULL)
+      {  if (flag == 0)
+         {  /* the height of the left subtree of [p] is increased */
+            if (p->bal > 0)
+            {  p->bal = 0;
+               break;
+            }
+            if (p->bal < 0)
+            {  rotate_subtree(tree, p);
+               break;
+            }
+            p->bal = -1; flag = p->flag; p = p->up;
+         }
+         else
+         {  /* the height of the right subtree of [p] is increased */
+            if (p->bal < 0)
+            {  p->bal = 0;
+               break;
+            }
+            if (p->bal > 0)
+            {  rotate_subtree(tree, p);
+               break;
+            }
+            p->bal = +1; flag = p->flag; p = p->up;
+         }
+      }
+      /* if the root has been reached, the height of the entire tree is
+         increased */
+      if (p == NULL) tree->height++;
+      return r;
+}
+
+void avl_set_node_type(AVLNODE *node, int type)
+{     /* assign the type field of specified node */
+      node->type = type;
+      return;
+}
+
+void avl_set_node_link(AVLNODE *node, void *link)
+{     /* assign the link field of specified node */
+      node->link = link;
+      return;
+}
+
+AVLNODE *avl_find_node(AVL *tree, const void *key)
+{     /* find node in AVL tree */
+      AVLNODE *p;
+      int c;
+      p = tree->root;
+      while (p != NULL)
+      {  c = tree->fcmp(tree->info, key, p->key);
+         if (c == 0) break;
+         p = (c < 0 ? p->left : p->right);
+      }
+      return p;
+}
+
+int avl_get_node_type(AVLNODE *node)
+{     /* retrieve the type field of specified node */
+      return node->type;
+}
+
+void *avl_get_node_link(AVLNODE *node)
+{     /* retrieve the link field of specified node */
+      return node->link;
+}
+
+static AVLNODE *find_next_node(AVL *tree, AVLNODE *node)
+{     /* find next node in AVL tree */
+      AVLNODE *p, *q;
+      if (tree->root == NULL) return NULL;
+      p = node;
+      q = (p == NULL ? tree->root : p->right);
+      if (q == NULL)
+      {  /* go upstairs from the left subtree */
+         for (;;)
+         {  q = p->up;
+            if (q == NULL) break;
+            if (p->flag == 0) break;
+            p = q;
+         }
+      }
+      else
+      {  /* go downstairs into the right subtree */
+         for (;;)
+         {  p = q->left;
+            if (p == NULL) break;
+            q = p;
+         }
+      }
+      return q;
+}
+
+void avl_delete_node(AVL *tree, AVLNODE *node)
+{     /* delete specified node from AVL tree */
+      AVLNODE *f, *p, *q, *r, *s, *x, *y;
+      short int flag;
+      p = node;
+      /* if both subtrees of the specified node are non-empty, the node
+         should be interchanged with the next one, at least one subtree
+         of which is always empty */
+      if (p->left == NULL || p->right == NULL) goto skip;
+      f = p->up; q = p->left;
+      r = find_next_node(tree, p); s = r->right;
+      if (p->right == r)
+      {  if (f == NULL)
+            tree->root = r;
+         else
+            if (p->flag == 0) f->left = r; else f->right = r;
+         r->rank = p->rank; r->up = f;
+         r->flag = p->flag; r->bal = p->bal;
+         r->left = q; r->right = p;
+         q->up = r;
+         p->rank = 1; p->up = r; p->flag = 1;
+         p->bal = (short int)(s == NULL ? 0 : +1);
+         p->left = NULL; p->right = s;
+         if (s != NULL) s->up = p;
+      }
+      else
+      {  x = p->right; y = r->up;
+         if (f == NULL)
+            tree->root = r;
+         else
+            if (p->flag == 0) f->left = r; else f->right = r;
+         r->rank = p->rank; r->up = f;
+         r->flag = p->flag; r->bal = p->bal;
+         r->left = q; r->right = x;
+         q->up = r; x->up = r; y->left = p;
+         p->rank = 1; p->up = y; p->flag = 0;
+         p->bal = (short int)(s == NULL ? 0 : +1);
+         p->left = NULL; p->right = s;
+         if (s != NULL) s->up = p;
+      }
+skip: /* now the specified node [p] has at least one empty subtree;
+         go upstairs to the root and adjust the rank field of all nodes
+         affected by deletion */
+      q = p; f = q->up;
+      while (f != NULL)
+      {  if (q->flag == 0) f->rank--;
+         q = f; f = q->up;
+      }
+      /* delete the specified node from the tree */
+      f = p->up; flag = p->flag;
+      q = p->left != NULL ? p->left : p->right;
+      if (f == NULL)
+         tree->root = q;
+      else
+         if (flag == 0) f->left = q; else f->right = q;
+      if (q != NULL) q->up = f, q->flag = flag;
+      tree->size--;
+      /* go upstairs to the root and correct all subtrees affected by
+         deletion */
+      while (f != NULL)
+      {  if (flag == 0)
+         {  /* the height of the left subtree of [f] is decreased */
+            if (f->bal == 0)
+            {  f->bal = +1;
+               break;
+            }
+            if (f->bal < 0)
+               f->bal = 0;
+            else
+            {  f = rotate_subtree(tree, f);
+               if (f->bal < 0) break;
+            }
+            flag = f->flag; f = f->up;
+         }
+         else
+         {  /* the height of the right subtree of [f] is decreased */
+            if (f->bal == 0)
+            {  f->bal = -1;
+               break;
+            }
+            if (f->bal > 0)
+               f->bal = 0;
+            else
+            {  f = rotate_subtree(tree, f);
+               if (f->bal > 0) break;
+            }
+            flag = f->flag; f = f->up;
+         }
+      }
+      /* if the root has been reached, the height of the entire tree is
+         decreased */
+      if (f == NULL) tree->height--;
+      /* returns the deleted node to the memory pool */
+      dmp_free_atom(tree->pool, p, sizeof(AVLNODE));
+      return;
+}
+
+static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node)
+{     /* restore balance of AVL subtree */
+      AVLNODE *f, *p, *q, *r, *x, *y;
+      xassert(node != NULL);
+      p = node;
+      if (p->bal < 0)
+      {  /* perform negative (left) rotation */
+         f = p->up; q = p->left; r = q->right;
+         if (q->bal <= 0)
+         {  /* perform single negative rotation */
+            if (f == NULL)
+               tree->root = q;
+            else
+               if (p->flag == 0) f->left = q; else f->right = q;
+            p->rank -= q->rank;
+            q->up = f; q->flag = p->flag; q->bal++; q->right = p;
+            p->up = q; p->flag = 1;
+            p->bal = (short int)(-q->bal); p->left = r;
+            if (r != NULL) r->up = p, r->flag = 0;
+            node = q;
+         }
+         else
+         {  /* perform double negative rotation */
+            x = r->left; y = r->right;
+            if (f == NULL)
+               tree->root = r;
+            else
+               if (p->flag == 0) f->left = r; else f->right = r;
+            p->rank -= (q->rank + r->rank);
+            r->rank += q->rank;
+            p->bal = (short int)(r->bal >= 0 ? 0 : +1);
+            q->bal = (short int)(r->bal <= 0 ? 0 : -1);
+            r->up = f; r->flag = p->flag; r->bal = 0;
+            r->left = q; r->right = p;
+            p->up = r; p->flag = 1; p->left = y;
+            q->up = r; q->flag = 0; q->right = x;
+            if (x != NULL) x->up = q, x->flag = 1;
+            if (y != NULL) y->up = p, y->flag = 0;
+            node = r;
+         }
+      }
+      else
+      {  /* perform positive (right) rotation */
+         f = p->up; q = p->right; r = q->left;
+         if (q->bal >= 0)
+         {  /* perform single positive rotation */
+            if (f == NULL)
+               tree->root = q;
+            else
+               if (p->flag == 0) f->left = q; else f->right = q;
+            q->rank += p->rank;
+            q->up = f; q->flag = p->flag; q->bal--; q->left = p;
+            p->up = q; p->flag = 0;
+            p->bal = (short int)(-q->bal); p->right = r;
+            if (r != NULL) r->up = p, r->flag = 1;
+            node = q;
+         }
+         else
+         {  /* perform double positive rotation */
+            x = r->left; y = r->right;
+            if (f == NULL)
+               tree->root = r;
+            else
+               if (p->flag == 0) f->left = r; else f->right = r;
+            q->rank -= r->rank;
+            r->rank += p->rank;
+            p->bal = (short int)(r->bal <= 0 ? 0 : -1);
+            q->bal = (short int)(r->bal >= 0 ? 0 : +1);
+            r->up = f; r->flag = p->flag; r->bal = 0;
+            r->left = p; r->right = q;
+            p->up = r; p->flag = 0; p->right = x;
+            q->up = r; q->flag = 1; q->left = y;
+            if (x != NULL) x->up = p, x->flag = 1;
+            if (y != NULL) y->up = q, y->flag = 0;
+            node = r;
+         }
+      }
+      return node;
+}
+
+void avl_delete_tree(AVL *tree)
+{     /* delete AVL tree */
+      dmp_delete_pool(tree->pool);
+      xfree(tree);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpavl.h
===================================================================
--- deps/glpk/src/glpavl.h	(revision 9)
+++ deps/glpk/src/glpavl.h	(revision 9)
@@ -0,0 +1,123 @@
+/* glpavl.h (binary search tree) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPAVL_H
+#define GLPAVL_H
+
+#include "glpdmp.h"
+
+typedef struct AVL AVL;
+typedef struct AVLNODE AVLNODE;
+
+struct AVL
+{     /* AVL tree (Adelson-Velsky & Landis binary search tree) */
+      DMP *pool;
+      /* memory pool for allocating nodes */
+      AVLNODE *root;
+      /* pointer to the root node */
+      int (*fcmp)(void *info, const void *key1, const void *key2);
+      /* application-defined key comparison routine */
+      void *info;
+      /* transit pointer passed to the routine fcmp */
+      int size;
+      /* the tree size (the total number of nodes) */
+      int height;
+      /* the tree height */
+};
+
+struct AVLNODE
+{     /* node of AVL tree */
+      const void *key;
+      /* pointer to the node key (data structure for representing keys
+         is supplied by the application) */
+      int rank;
+      /* node rank = relative position of the node in its own subtree =
+         the number of nodes in the left subtree plus one */
+      int type;
+      /* reserved for the application specific information */
+      void *link;
+      /* reserved for the application specific information */
+      AVLNODE *up;
+      /* pointer to the parent node */
+      short int flag;
+      /* node flag:
+         0 - this node is the left child of its parent (or this node is
+             the root of the tree and has no parent)
+         1 - this node is the right child of its parent */
+      short int bal;
+      /* node balance = the difference between heights of the right and
+         left subtrees:
+         -1 - the left subtree is higher than the right one;
+          0 - the left and right subtrees have the same height;
+         +1 - the left subtree is lower than the right one */
+      AVLNODE *left;
+      /* pointer to the root of the left subtree */
+      AVLNODE *right;
+      /* pointer to the root of the right subtree */
+};
+
+#define avl_create_tree _glp_avl_create_tree
+AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1,
+      const void *key2), void *info);
+/* create AVL tree */
+
+#define avl_strcmp _glp_avl_strcmp
+int avl_strcmp(void *info, const void *key1, const void *key2);
+/* compare character string keys */
+
+#define avl_insert_node _glp_avl_insert_node
+AVLNODE *avl_insert_node(AVL *tree, const void *key);
+/* insert new node into AVL tree */
+
+#define avl_set_node_type _glp_avl_set_node_type
+void avl_set_node_type(AVLNODE *node, int type);
+/* assign the type field of specified node */
+
+#define avl_set_node_link _glp_avl_set_node_link
+void avl_set_node_link(AVLNODE *node, void *link);
+/* assign the link field of specified node */
+
+#define avl_find_node _glp_avl_find_node
+AVLNODE *avl_find_node(AVL *tree, const void *key);
+/* find node in AVL tree */
+
+#define avl_get_node_type _glp_avl_get_node_type
+int avl_get_node_type(AVLNODE *node);
+/* retrieve the type field of specified node */
+
+#define avl_get_node_link _glp_avl_get_node_link
+void *avl_get_node_link(AVLNODE *node);
+/* retrieve the link field of specified node */
+
+#define avl_delete_node _glp_avl_delete_node
+void avl_delete_node(AVL *tree, AVLNODE *node);
+/* delete specified node from AVL tree */
+
+#define avl_delete_tree _glp_avl_delete_tree
+void avl_delete_tree(AVL *tree);
+/* delete AVL tree */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpbfd.c
===================================================================
--- deps/glpk/src/glpbfd.c	(revision 9)
+++ deps/glpk/src/glpbfd.c	(revision 9)
@@ -0,0 +1,481 @@
+/* glpbfd.c (LP basis factorization driver) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+typedef struct BFD BFD;
+
+#define GLPBFD_PRIVATE
+#include "glpapi.h"
+#include "glpfhv.h"
+#include "glplpf.h"
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the basis matrix */
+
+struct BFD
+{     /* LP basis factorization */
+      int valid;
+      /* factorization is valid only if this flag is set */
+      int type;
+      /* factorization type:
+         GLP_BF_FT - LUF + Forrest-Tomlin
+         GLP_BF_BG - LUF + Schur compl. + Bartels-Golub
+         GLP_BF_GR - LUF + Schur compl. + Givens rotation */
+      FHV *fhv;
+      /* LP basis factorization (GLP_BF_FT) */
+      LPF *lpf;
+      /* LP basis factorization (GLP_BF_BG, GLP_BF_GR) */
+      int lu_size;      /* luf.sv_size */
+      double piv_tol;   /* luf.piv_tol */
+      int piv_lim;      /* luf.piv_lim */
+      int suhl;         /* luf.suhl */
+      double eps_tol;   /* luf.eps_tol */
+      double max_gro;   /* luf.max_gro */
+      int nfs_max;      /* fhv.hh_max */
+      double upd_tol;   /* fhv.upd_tol */
+      int nrs_max;      /* lpf.n_max */
+      int rs_size;      /* lpf.v_size */
+      /* internal control parameters */
+      int upd_lim;
+      /* the factorization update limit */
+      int upd_cnt;
+      /* the factorization update count */
+};
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_create_it - create LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  BFD *bfd_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_create_it creates a program object, which represents
+*  a factorization of LP basis.
+*
+*  RETURNS
+*
+*  The routine bfd_create_it returns a pointer to the object created. */
+
+BFD *bfd_create_it(void)
+{     BFD *bfd;
+      bfd = xmalloc(sizeof(BFD));
+      bfd->valid = 0;
+      bfd->type = GLP_BF_FT;
+      bfd->fhv = NULL;
+      bfd->lpf = NULL;
+      bfd->lu_size = 0;
+      bfd->piv_tol = 0.10;
+      bfd->piv_lim = 4;
+      bfd->suhl = 1;
+      bfd->eps_tol = 1e-15;
+      bfd->max_gro = 1e+10;
+      bfd->nfs_max = 100;
+      bfd->upd_tol = 1e-6;
+      bfd->nrs_max = 100;
+      bfd->rs_size = 1000;
+      bfd->upd_lim = -1;
+      bfd->upd_cnt = 0;
+      return bfd;
+}
+
+/**********************************************************************/
+
+void bfd_set_parm(BFD *bfd, const void *_parm)
+{     /* change LP basis factorization control parameters */
+      const glp_bfcp *parm = _parm;
+      xassert(bfd != NULL);
+      bfd->type = parm->type;
+      bfd->lu_size = parm->lu_size;
+      bfd->piv_tol = parm->piv_tol;
+      bfd->piv_lim = parm->piv_lim;
+      bfd->suhl = parm->suhl;
+      bfd->eps_tol = parm->eps_tol;
+      bfd->max_gro = parm->max_gro;
+      bfd->nfs_max = parm->nfs_max;
+      bfd->upd_tol = parm->upd_tol;
+      bfd->nrs_max = parm->nrs_max;
+      bfd->rs_size = parm->rs_size;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_factorize - compute LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  int bfd_factorize(BFD *bfd, int m, int bh[], int (*col)(void *info,
+*     int j, int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_factorize computes the factorization of the basis
+*  matrix B specified by the routine col.
+*
+*  The parameter bfd specified the basis factorization data structure
+*  created with the routine bfd_create_it.
+*
+*  The parameter m specifies the order of B, m > 0.
+*
+*  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
+*  number of j-th column of B in some original matrix. The array bh is
+*  optional and can be specified as NULL.
+*
+*  The formal routine col specifies the matrix B to be factorized. To
+*  obtain j-th column of A the routine bfd_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully computed.
+*
+*  BFD_ESING
+*     The specified matrix is singular within the working precision.
+*
+*  BFD_ECOND
+*     The specified matrix is ill-conditioned.
+*
+*  For more details see comments to the routine luf_factorize. */
+
+int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info)
+{     LUF *luf;
+      int nov, ret;
+      xassert(bfd != NULL);
+      xassert(1 <= m && m <= M_MAX);
+      /* invalidate the factorization */
+      bfd->valid = 0;
+      /* create the factorization, if necessary */
+      nov = 0;
+      switch (bfd->type)
+      {  case GLP_BF_FT:
+            if (bfd->lpf != NULL)
+               lpf_delete_it(bfd->lpf), bfd->lpf = NULL;
+            if (bfd->fhv == NULL)
+               bfd->fhv = fhv_create_it(), nov = 1;
+            break;
+         case GLP_BF_BG:
+         case GLP_BF_GR:
+            if (bfd->fhv != NULL)
+               fhv_delete_it(bfd->fhv), bfd->fhv = NULL;
+            if (bfd->lpf == NULL)
+               bfd->lpf = lpf_create_it(), nov = 1;
+            break;
+         default:
+            xassert(bfd != bfd);
+      }
+      /* set control parameters specific to LUF */
+      if (bfd->fhv != NULL)
+         luf = bfd->fhv->luf;
+      else if (bfd->lpf != NULL)
+         luf = bfd->lpf->luf;
+      else
+         xassert(bfd != bfd);
+      if (nov) luf->new_sva = bfd->lu_size;
+      luf->piv_tol = bfd->piv_tol;
+      luf->piv_lim = bfd->piv_lim;
+      luf->suhl = bfd->suhl;
+      luf->eps_tol = bfd->eps_tol;
+      luf->max_gro = bfd->max_gro;
+      /* set control parameters specific to FHV */
+      if (bfd->fhv != NULL)
+      {  if (nov) bfd->fhv->hh_max = bfd->nfs_max;
+         bfd->fhv->upd_tol = bfd->upd_tol;
+      }
+      /* set control parameters specific to LPF */
+      if (bfd->lpf != NULL)
+      {  if (nov) bfd->lpf->n_max = bfd->nrs_max;
+         if (nov) bfd->lpf->v_size = bfd->rs_size;
+      }
+      /* try to factorize the basis matrix */
+      if (bfd->fhv != NULL)
+      {  switch (fhv_factorize(bfd->fhv, m, col, info))
+         {  case 0:
+               break;
+            case FHV_ESING:
+               ret = BFD_ESING;
+               goto done;
+            case FHV_ECOND:
+               ret = BFD_ECOND;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else if (bfd->lpf != NULL)
+      {  switch (lpf_factorize(bfd->lpf, m, bh, col, info))
+         {  case 0:
+               /* set the Schur complement update type */
+               switch (bfd->type)
+               {  case GLP_BF_BG:
+                     /* Bartels-Golub update */
+                     bfd->lpf->scf->t_opt = SCF_TBG;
+                     break;
+                  case GLP_BF_GR:
+                     /* Givens rotation update */
+                     bfd->lpf->scf->t_opt = SCF_TGR;
+                     break;
+                  default:
+                     xassert(bfd != bfd);
+               }
+               break;
+            case LPF_ESING:
+               ret = BFD_ESING;
+               goto done;
+            case LPF_ECOND:
+               ret = BFD_ECOND;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else
+         xassert(bfd != bfd);
+      /* the basis matrix has been successfully factorized */
+      bfd->valid = 1;
+      bfd->upd_cnt = 0;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  void bfd_ftran(BFD *bfd, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void bfd_ftran(BFD *bfd, double x[])
+{     xassert(bfd != NULL);
+      xassert(bfd->valid);
+      if (bfd->fhv != NULL)
+         fhv_ftran(bfd->fhv, x);
+      else if (bfd->lpf != NULL)
+         lpf_ftran(bfd->lpf, x);
+      else
+         xassert(bfd != bfd);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  void bfd_btran(BFD *bfd, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix B, x is the vector of unknowns to be computed, b is the vector
+*  of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void bfd_btran(BFD *bfd, double x[])
+{     xassert(bfd != NULL);
+      xassert(bfd->valid);
+      if (bfd->fhv != NULL)
+         fhv_btran(bfd->fhv, x);
+      else if (bfd->lpf != NULL)
+         lpf_btran(bfd->lpf, x);
+      else
+         xassert(bfd != bfd);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_update_it - update LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_update_it updates the factorization of the basis
+*  matrix B after replacing its j-th column by a new vector.
+*
+*  The parameter j specifies the number of column of B, which has been
+*  replaced, 1 <= j <= m, where m is the order of B.
+*
+*  The parameter bh specifies the basis header entry for the new column
+*  of B, which is the number of the new column in some original matrix.
+*  This parameter is optional and can be specified as 0.
+*
+*  Row indices and numerical values of non-zero elements of the new
+*  column of B should be placed in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], resp., where len is the number of non-zeros
+*  in the column. Neither zero nor duplicate elements are allowed.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  BFD_ESING
+*     New basis matrix is singular within the working precision.
+*
+*  BFD_ECHECK
+*     The factorization is inaccurate.
+*
+*  BFD_ELIMIT
+*     Factorization update limit has been reached.
+*
+*  BFD_EROOM
+*     Overflow of the sparse vector area.
+*
+*  In case of non-zero return code the factorization becomes invalid.
+*  It should not be used until it has been recomputed with the routine
+*  bfd_factorize. */
+
+int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
+      const double val[])
+{     int ret;
+      xassert(bfd != NULL);
+      xassert(bfd->valid);
+      /* try to update the factorization */
+      if (bfd->fhv != NULL)
+      {  switch (fhv_update_it(bfd->fhv, j, len, ind, val))
+         {  case 0:
+               break;
+            case FHV_ESING:
+               bfd->valid = 0;
+               ret = BFD_ESING;
+               goto done;
+            case FHV_ECHECK:
+               bfd->valid = 0;
+               ret = BFD_ECHECK;
+               goto done;
+            case FHV_ELIMIT:
+               bfd->valid = 0;
+               ret = BFD_ELIMIT;
+               goto done;
+            case FHV_EROOM:
+               bfd->valid = 0;
+               ret = BFD_EROOM;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else if (bfd->lpf != NULL)
+      {  switch (lpf_update_it(bfd->lpf, j, bh, len, ind, val))
+         {  case 0:
+               break;
+            case LPF_ESING:
+               bfd->valid = 0;
+               ret = BFD_ESING;
+               goto done;
+            case LPF_ELIMIT:
+               bfd->valid = 0;
+               ret = BFD_ELIMIT;
+               goto done;
+            default:
+               xassert(bfd != bfd);
+         }
+      }
+      else
+         xassert(bfd != bfd);
+      /* the factorization has been successfully updated */
+      /* increase the update count */
+      bfd->upd_cnt++;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/**********************************************************************/
+
+int bfd_get_count(BFD *bfd)
+{     /* determine factorization update count */
+      xassert(bfd != NULL);
+      xassert(bfd->valid);
+      return bfd->upd_cnt;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bfd_delete_it - delete LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpbfd.h"
+*  void bfd_delete_it(BFD *bfd);
+*
+*  DESCRIPTION
+*
+*  The routine bfd_delete_it deletes LP basis factorization specified
+*  by the parameter fhv and frees all memory allocated to this program
+*  object. */
+
+void bfd_delete_it(BFD *bfd)
+{     xassert(bfd != NULL);
+      if (bfd->fhv != NULL)
+         fhv_delete_it(bfd->fhv);
+      if (bfd->lpf != NULL)
+         lpf_delete_it(bfd->lpf);
+      xfree(bfd);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpbfd.h
===================================================================
--- deps/glpk/src/glpbfd.h	(revision 9)
+++ deps/glpk/src/glpbfd.h	(revision 9)
@@ -0,0 +1,75 @@
+/* glpbfd.h (LP basis factorization driver) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPBFD_H
+#define GLPBFD_H
+
+#ifndef GLPBFD_PRIVATE
+typedef struct { double _opaque_bfd[100]; } BFD;
+#endif
+
+/* return codes: */
+#define BFD_ESING    1  /* singular matrix */
+#define BFD_ECOND    2  /* ill-conditioned matrix */
+#define BFD_ECHECK   3  /* insufficient accuracy */
+#define BFD_ELIMIT   4  /* update limit reached */
+#define BFD_EROOM    5  /* SVA overflow */
+
+#define bfd_create_it _glp_bfd_create_it
+BFD *bfd_create_it(void);
+/* create LP basis factorization */
+
+#define bfd_set_parm _glp_bfd_set_parm
+void bfd_set_parm(BFD *bfd, const void *parm);
+/* change LP basis factorization control parameters */
+
+#define bfd_factorize _glp_bfd_factorize
+int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info);
+/* compute LP basis factorization */
+
+#define bfd_ftran _glp_bfd_ftran
+void bfd_ftran(BFD *bfd, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+#define bfd_btran _glp_bfd_btran
+void bfd_btran(BFD *bfd, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+#define bfd_update_it _glp_bfd_update_it
+int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
+      const double val[]);
+/* update LP basis factorization */
+
+#define bfd_get_count _glp_bfd_get_count
+int bfd_get_count(BFD *bfd);
+/* determine factorization update count */
+
+#define bfd_delete_it _glp_bfd_delete_it
+void bfd_delete_it(BFD *bfd);
+/* delete LP basis factorization */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpbfx.c
===================================================================
--- deps/glpk/src/glpbfx.c	(revision 9)
+++ deps/glpk/src/glpbfx.c	(revision 9)
@@ -0,0 +1,91 @@
+/* glpbfx.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+typedef struct BFX BFX;
+#define GLPBFX_DEFINED
+#include "glpbfx.h"
+#include "glpenv.h"
+#include "glplux.h"
+
+struct BFX
+{     int valid;
+      LUX *lux;
+};
+
+BFX *bfx_create_binv(void)
+{     /* create factorization of the basis matrix */
+      BFX *bfx;
+      bfx = xmalloc(sizeof(BFX));
+      bfx->valid = 0;
+      bfx->lux = NULL;
+      return bfx;
+}
+
+int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
+      int ind[], mpq_t val[]), void *info)
+{     /* compute factorization of the basis matrix */
+      int ret;
+      xassert(m > 0);
+      if (binv->lux != NULL && binv->lux->n != m)
+      {  lux_delete(binv->lux);
+         binv->lux = NULL;
+      }
+      if (binv->lux == NULL)
+         binv->lux = lux_create(m);
+      ret = lux_decomp(binv->lux, col, info);
+      binv->valid = (ret == 0);
+      return ret;
+}
+
+void bfx_ftran(BFX *binv, mpq_t x[], int save)
+{     /* perform forward transformation (FTRAN) */
+      xassert(binv->valid);
+      lux_solve(binv->lux, 0, x);
+      xassert(save == save);
+      return;
+}
+
+void bfx_btran(BFX *binv, mpq_t x[])
+{     /* perform backward transformation (BTRAN) */
+      xassert(binv->valid);
+      lux_solve(binv->lux, 1, x);
+      return;
+}
+
+int bfx_update(BFX *binv, int j)
+{     /* update factorization of the basis matrix */
+      xassert(binv->valid);
+      xassert(1 <= j && j <= binv->lux->n);
+      return 1;
+}
+
+void bfx_delete_binv(BFX *binv)
+{     /* delete factorization of the basis matrix */
+      if (binv->lux != NULL)
+         lux_delete(binv->lux);
+      xfree(binv);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpbfx.h
===================================================================
--- deps/glpk/src/glpbfx.h	(revision 9)
+++ deps/glpk/src/glpbfx.h	(revision 9)
@@ -0,0 +1,71 @@
+/* glpbfx.h (basis factorization interface, bignum arithmetic) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPBFX_H
+#define GLPBFX_H
+
+#include "glpgmp.h"
+
+#ifndef GLPBFX_DEFINED
+#define GLPBFX_DEFINED
+typedef struct { double _opaque_bfx; } BFX;
+#endif
+
+#define bfx_create_binv       _glp_bfx_create_binv
+#define bfx_is_valid          _glp_bfx_is_valid
+#define bfx_invalidate        _glp_bfx_invalidate
+#define bfx_factorize         _glp_bfx_factorize
+#define bfx_ftran             _glp_bfx_ftran
+#define bfx_btran             _glp_bfx_btran
+#define bfx_update            _glp_bfx_update
+#define bfx_delete_binv       _glp_bfx_delete_binv
+
+BFX *bfx_create_binv(void);
+/* create factorization of the basis matrix */
+
+int bfx_is_valid(BFX *binv);
+/* check if factorization is valid */
+
+void bfx_invalidate(BFX *binv);
+/* invalidate factorization of the basis matrix */
+
+int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j,
+      int ind[], mpq_t val[]), void *info);
+/* compute factorization of the basis matrix */
+
+void bfx_ftran(BFX *binv, mpq_t x[], int save);
+/* perform forward transformation (FTRAN) */
+
+void bfx_btran(BFX *binv, mpq_t x[]);
+/* perform backward transformation (BTRAN) */
+
+int bfx_update(BFX *binv, int j);
+/* update factorization of the basis matrix */
+
+void bfx_delete_binv(BFX *binv);
+/* delete factorization of the basis matrix */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpcpx.c
===================================================================
--- deps/glpk/src/glpcpx.c	(revision 9)
+++ deps/glpk/src/glpcpx.c	(revision 9)
@@ -0,0 +1,1239 @@
+/* glpcpx.c (CPLEX LP format routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_cpxcp - initialize CPLEX LP format control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_cpxcp(glp_cpxcp *parm):
+*
+*  The routine glp_init_cpxcp initializes control parameters used by
+*  the CPLEX LP input/output routines glp_read_lp and glp_write_lp with
+*  default values.
+*
+*  Default values of the control parameters are stored in the glp_cpxcp
+*  structure, which the parameter parm points to. */
+
+void glp_init_cpxcp(glp_cpxcp *parm)
+{     xassert(parm != NULL);
+      return;
+}
+
+static void check_parm(const char *func, const glp_cpxcp *parm)
+{     /* check control parameters */
+      xassert(func != NULL);
+      xassert(parm != NULL);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_lp - read problem data in CPLEX LP format
+*
+*  SYNOPSIS
+*
+*  int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char
+*     *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_lp reads problem data in CPLEX LP format from
+*  a text file.
+*
+*  The parameter parm is a pointer to the structure glp_cpxcp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  read.
+*
+*  Note that before reading data the current content of the problem
+*  object is completely erased with the routine glp_erase_prob.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_read_lp returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* LP/MIP problem object */
+      const glp_cpxcp *parm;
+      /* pointer to control parameters */
+      const char *fname;
+      /* name of input CPLEX LP file */
+      XFILE *fp;
+      /* stream assigned to input CPLEX LP file */
+      jmp_buf jump;
+      /* label for go to in case of error */
+      int count;
+      /* line count */
+      int c;
+      /* current character or XEOF */
+      int token;
+      /* current token: */
+#define T_EOF        0x00  /* end of file */
+#define T_MINIMIZE   0x01  /* keyword 'minimize' */
+#define T_MAXIMIZE   0x02  /* keyword 'maximize' */
+#define T_SUBJECT_TO 0x03  /* keyword 'subject to' */
+#define T_BOUNDS     0x04  /* keyword 'bounds' */
+#define T_GENERAL    0x05  /* keyword 'general' */
+#define T_INTEGER    0x06  /* keyword 'integer' */
+#define T_BINARY     0x07  /* keyword 'binary' */
+#define T_END        0x08  /* keyword 'end' */
+#define T_NAME       0x09  /* symbolic name */
+#define T_NUMBER     0x0A  /* numeric constant */
+#define T_PLUS       0x0B  /* delimiter '+' */
+#define T_MINUS      0x0C  /* delimiter '-' */
+#define T_COLON      0x0D  /* delimiter ':' */
+#define T_LE         0x0E  /* delimiter '<=' */
+#define T_GE         0x0F  /* delimiter '>=' */
+#define T_EQ         0x10  /* delimiter '=' */
+      char image[255+1];
+      /* image of current token */
+      int imlen;
+      /* length of token image */
+      double value;
+      /* value of numeric constant */
+      int n_max;
+      /* length of the following five arrays (enlarged automatically,
+         if necessary) */
+      int *ind; /* int ind[1+n_max]; */
+      double *val; /* double val[1+n_max]; */
+      char *flag; /* char flag[1+n_max]; */
+      /* working arrays used to construct linear forms */
+      double *lb; /* double lb[1+n_max]; */
+      double *ub; /* double ub[1+n_max]; */
+      /* lower and upper bounds of variables (columns) */
+};
+
+#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~"
+/* characters, which may appear in symbolic names */
+
+static void error(struct csa *csa, const char *fmt, ...)
+{     /* print error message and terminate processing */
+      va_list arg;
+      xprintf("%s:%d: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      longjmp(csa->jump, 1);
+      /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{     /* print warning message and continue processing */
+      va_list arg;
+      xprintf("%s:%d: warning: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      return;
+}
+
+static void read_char(struct csa *csa)
+{     /* read next character from input file */
+      int c;
+      xassert(csa->c != XEOF);
+      if (csa->c == '\n') csa->count++;
+      c = xfgetc(csa->fp);
+      if (c < 0)
+      {  if (xferror(csa->fp))
+            error(csa, "read error - %s\n", xerrmsg());
+         else if (csa->c == '\n')
+         {  csa->count--;
+            c = XEOF;
+         }
+         else
+         {  warning(csa, "missing final end of line\n");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+         error(csa, "invalid control character 0x%02X\n", c);
+      csa->c = c;
+      return;
+}
+
+static void add_char(struct csa *csa)
+{     /* append current character to current token */
+      if (csa->imlen == sizeof(csa->image)-1)
+         error(csa, "token `%.15s...' too long\n", csa->image);
+      csa->image[csa->imlen++] = (char)csa->c;
+      csa->image[csa->imlen] = '\0';
+      read_char(csa);
+      return;
+}
+
+static int the_same(char *s1, char *s2)
+{     /* compare two character strings ignoring case sensitivity */
+      for (; *s1 != '\0'; s1++, s2++)
+      {  if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2))
+            return 0;
+      }
+      return 1;
+}
+
+static void scan_token(struct csa *csa)
+{     /* scan next token */
+      int flag;
+      csa->token = -1;
+      csa->image[0] = '\0';
+      csa->imlen = 0;
+      csa->value = 0.0;
+loop: flag = 0;
+      /* skip non-significant characters */
+      while (csa->c == ' ') read_char(csa);
+      /* recognize and scan current token */
+      if (csa->c == XEOF)
+         csa->token = T_EOF;
+      else if (csa->c == '\n')
+      {  read_char(csa);
+         /* if the next character is letter, it may begin a keyword */
+         if (isalpha(csa->c))
+         {  flag = 1;
+            goto name;
+         }
+         goto loop;
+      }
+      else if (csa->c == '\\')
+      {  /* comment; ignore everything until end-of-line */
+         while (csa->c != '\n') read_char(csa);
+         goto loop;
+      }
+      else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET,
+         csa->c) != NULL)
+name: {  /* symbolic name */
+         csa->token = T_NAME;
+         while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL)
+            add_char(csa);
+         if (flag)
+         {  /* check for keyword */
+            if (the_same(csa->image, "minimize"))
+               csa->token = T_MINIMIZE;
+            else if (the_same(csa->image, "minimum"))
+               csa->token = T_MINIMIZE;
+            else if (the_same(csa->image, "min"))
+               csa->token = T_MINIMIZE;
+            else if (the_same(csa->image, "maximize"))
+               csa->token = T_MAXIMIZE;
+            else if (the_same(csa->image, "maximum"))
+               csa->token = T_MAXIMIZE;
+            else if (the_same(csa->image, "max"))
+               csa->token = T_MAXIMIZE;
+            else if (the_same(csa->image, "subject"))
+            {  if (csa->c == ' ')
+               {  read_char(csa);
+                  if (tolower(csa->c) == 't')
+                  {  csa->token = T_SUBJECT_TO;
+                     csa->image[csa->imlen++] = ' ';
+                     csa->image[csa->imlen] = '\0';
+                     add_char(csa);
+                     if (tolower(csa->c) != 'o')
+                        error(csa, "keyword `subject to' incomplete\n");
+                     add_char(csa);
+                     if (isalpha(csa->c))
+                        error(csa, "keyword `%s%c...' not recognized\n",
+                           csa->image, csa->c);
+                  }
+               }
+            }
+            else if (the_same(csa->image, "such"))
+            {  if (csa->c == ' ')
+               {  read_char(csa);
+                  if (tolower(csa->c) == 't')
+                  {  csa->token = T_SUBJECT_TO;
+                     csa->image[csa->imlen++] = ' ';
+                     csa->image[csa->imlen] = '\0';
+                     add_char(csa);
+                     if (tolower(csa->c) != 'h')
+err:                    error(csa, "keyword `such that' incomplete\n");
+                     add_char(csa);
+                     if (tolower(csa->c) != 'a') goto err;
+                     add_char(csa);
+                     if (tolower(csa->c) != 't') goto err;
+                     add_char(csa);
+                     if (isalpha(csa->c))
+                        error(csa, "keyword `%s%c...' not recognized\n",
+                           csa->image, csa->c);
+                  }
+               }
+            }
+            else if (the_same(csa->image, "st"))
+               csa->token = T_SUBJECT_TO;
+            else if (the_same(csa->image, "s.t."))
+               csa->token = T_SUBJECT_TO;
+            else if (the_same(csa->image, "st."))
+               csa->token = T_SUBJECT_TO;
+            else if (the_same(csa->image, "bounds"))
+               csa->token = T_BOUNDS;
+            else if (the_same(csa->image, "bound"))
+               csa->token = T_BOUNDS;
+            else if (the_same(csa->image, "general"))
+               csa->token = T_GENERAL;
+            else if (the_same(csa->image, "generals"))
+               csa->token = T_GENERAL;
+            else if (the_same(csa->image, "gen"))
+               csa->token = T_GENERAL;
+            else if (the_same(csa->image, "integer"))
+               csa->token = T_INTEGER;
+            else if (the_same(csa->image, "integers"))
+               csa->token = T_INTEGER;
+            else if (the_same(csa->image, "int"))
+              csa->token = T_INTEGER;
+            else if (the_same(csa->image, "binary"))
+               csa->token = T_BINARY;
+            else if (the_same(csa->image, "binaries"))
+               csa->token = T_BINARY;
+            else if (the_same(csa->image, "bin"))
+               csa->token = T_BINARY;
+            else if (the_same(csa->image, "end"))
+               csa->token = T_END;
+         }
+      }
+      else if (isdigit(csa->c) || csa->c == '.')
+      {  /* numeric constant */
+         csa->token = T_NUMBER;
+         /* scan integer part */
+         while (isdigit(csa->c)) add_char(csa);
+         /* scan optional fractional part (it is mandatory, if there is
+            no integer part) */
+         if (csa->c == '.')
+         {  add_char(csa);
+            if (csa->imlen == 1 && !isdigit(csa->c))
+               error(csa, "invalid use of decimal point\n");
+            while (isdigit(csa->c)) add_char(csa);
+         }
+         /* scan optional decimal exponent */
+         if (csa->c == 'e' || csa->c == 'E')
+         {  add_char(csa);
+            if (csa->c == '+' || csa->c == '-') add_char(csa);
+            if (!isdigit(csa->c))
+               error(csa, "numeric constant `%s' incomplete\n",
+                  csa->image);
+            while (isdigit(csa->c)) add_char(csa);
+         }
+         /* convert the numeric constant to floating-point */
+         if (str2num(csa->image, &csa->value))
+            error(csa, "numeric constant `%s' out of range\n",
+               csa->image);
+      }
+      else if (csa->c == '+')
+         csa->token = T_PLUS, add_char(csa);
+      else if (csa->c == '-')
+         csa->token = T_MINUS, add_char(csa);
+      else if (csa->c == ':')
+         csa->token = T_COLON, add_char(csa);
+      else if (csa->c == '<')
+      {  csa->token = T_LE, add_char(csa);
+         if (csa->c == '=') add_char(csa);
+      }
+      else if (csa->c == '>')
+      {  csa->token = T_GE, add_char(csa);
+         if (csa->c == '=') add_char(csa);
+      }
+      else if (csa->c == '=')
+      {  csa->token = T_EQ, add_char(csa);
+         if (csa->c == '<')
+            csa->token = T_LE, add_char(csa);
+         else if (csa->c == '>')
+            csa->token = T_GE, add_char(csa);
+      }
+      else
+         error(csa, "character `%c' not recognized\n", csa->c);
+      /* skip non-significant characters */
+      while (csa->c == ' ') read_char(csa);
+      return;
+}
+
+static int find_col(struct csa *csa, char *name)
+{     /* find column by its symbolic name */
+      int j;
+      j = glp_find_col(csa->P, name);
+      if (j == 0)
+      {  /* not found; create new column */
+         j = glp_add_cols(csa->P, 1);
+         glp_set_col_name(csa->P, j, name);
+         /* enlarge working arrays, if necessary */
+         if (csa->n_max < j)
+         {  int n_max = csa->n_max;
+            int *ind = csa->ind;
+            double *val = csa->val;
+            char *flag = csa->flag;
+            double *lb = csa->lb;
+            double *ub = csa->ub;
+            csa->n_max += csa->n_max;
+            csa->ind = xcalloc(1+csa->n_max, sizeof(int));
+            memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int));
+            xfree(ind);
+            csa->val = xcalloc(1+csa->n_max, sizeof(double));
+            memcpy(&csa->val[1], &val[1], n_max * sizeof(double));
+            xfree(val);
+            csa->flag = xcalloc(1+csa->n_max, sizeof(char));
+            memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
+            memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char));
+            xfree(flag);
+            csa->lb = xcalloc(1+csa->n_max, sizeof(double));
+            memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double));
+            xfree(lb);
+            csa->ub = xcalloc(1+csa->n_max, sizeof(double));
+            memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double));
+            xfree(ub);
+         }
+         csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX;
+      }
+      return j;
+}
+
+/***********************************************************************
+*  parse_linear_form - parse linear form
+*
+*  This routine parses the linear form using the following syntax:
+*
+*  <variable> ::= <symbolic name>
+*  <coefficient> ::= <numeric constant>
+*  <term> ::= <variable> | <numeric constant> <variable>
+*  <linear form> ::= <term> | + <term> | - <term> |
+*     <linear form> + <term> | <linear form> - <term>
+*
+*  The routine returns the number of terms in the linear form. */
+
+static int parse_linear_form(struct csa *csa)
+{     int j, k, len = 0, newlen;
+      double s, coef;
+loop: /* parse an optional sign */
+      if (csa->token == T_PLUS)
+         s = +1.0, scan_token(csa);
+      else if (csa->token == T_MINUS)
+         s = -1.0, scan_token(csa);
+      else
+         s = +1.0;
+      /* parse an optional coefficient */
+      if (csa->token == T_NUMBER)
+         coef = csa->value, scan_token(csa);
+      else
+         coef = 1.0;
+      /* parse a variable name */
+      if (csa->token != T_NAME)
+         error(csa, "missing variable name\n");
+      /* find the corresponding column */
+      j = find_col(csa, csa->image);
+      /* check if the variable is already used in the linear form */
+      if (csa->flag[j])
+         error(csa, "multiple use of variable `%s' not allowed\n",
+            csa->image);
+      /* add new term to the linear form */
+      len++, csa->ind[len] = j, csa->val[len] = s * coef;
+      /* and mark that the variable is used in the linear form */
+      csa->flag[j] = 1;
+      scan_token(csa);
+      /* if the next token is a sign, there is another term */
+      if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop;
+      /* clear marks of the variables used in the linear form */
+      for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0;
+      /* remove zero coefficients */
+      newlen = 0;
+      for (k = 1; k <= len; k++)
+      {  if (csa->val[k] != 0.0)
+         {  newlen++;
+            csa->ind[newlen] = csa->ind[k];
+            csa->val[newlen] = csa->val[k];
+         }
+      }
+      return newlen;
+}
+
+/***********************************************************************
+*  parse_objective - parse objective function
+*
+*  This routine parses definition of the objective function using the
+*  following syntax:
+*
+*  <obj sense> ::= minimize | minimum | min | maximize | maximum | max
+*  <obj name> ::= <empty> | <symbolic name> :
+*  <obj function> ::= <obj sense> <obj name> <linear form> */
+
+static void parse_objective(struct csa *csa)
+{     /* parse objective sense */
+      int k, len;
+      /* parse the keyword 'minimize' or 'maximize' */
+      if (csa->token == T_MINIMIZE)
+         glp_set_obj_dir(csa->P, GLP_MIN);
+      else if (csa->token == T_MAXIMIZE)
+         glp_set_obj_dir(csa->P, GLP_MAX);
+      else
+         xassert(csa != csa);
+      scan_token(csa);
+      /* parse objective name */
+      if (csa->token == T_NAME && csa->c == ':')
+      {  /* objective name is followed by a colon */
+         glp_set_obj_name(csa->P, csa->image);
+         scan_token(csa);
+         xassert(csa->token == T_COLON);
+         scan_token(csa);
+      }
+      else
+      {  /* objective name is not specified; use default */
+         glp_set_obj_name(csa->P, "obj");
+      }
+      /* parse linear form */
+      len = parse_linear_form(csa);
+      for (k = 1; k <= len; k++)
+         glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]);
+      return;
+}
+
+/***********************************************************************
+*  parse_constraints - parse constraints section
+*
+*  This routine parses the constraints section using the following
+*  syntax:
+*
+*  <row name> ::= <empty> | <symbolic name> :
+*  <row sense> ::= < | <= | =< | > | >= | => | =
+*  <right-hand side> ::= <numeric constant> | + <numeric constant> |
+*     - <numeric constant>
+*  <constraint> ::= <row name> <linear form> <row sense>
+*     <right-hand side>
+*  <subject to> ::= subject to | such that | st | s.t. | st.
+*  <constraints section> ::= <subject to> <constraint> |
+*     <constraints section> <constraint> */
+
+static void parse_constraints(struct csa *csa)
+{     int i, len, type;
+      double s;
+      /* parse the keyword 'subject to' */
+      xassert(csa->token == T_SUBJECT_TO);
+      scan_token(csa);
+loop: /* create new row (constraint) */
+      i = glp_add_rows(csa->P, 1);
+      /* parse row name */
+      if (csa->token == T_NAME && csa->c == ':')
+      {  /* row name is followed by a colon */
+         if (glp_find_row(csa->P, csa->image) != 0)
+            error(csa, "constraint `%s' multiply defined\n",
+               csa->image);
+         glp_set_row_name(csa->P, i, csa->image);
+         scan_token(csa);
+         xassert(csa->token == T_COLON);
+         scan_token(csa);
+      }
+      else
+      {  /* row name is not specified; use default */
+         char name[50];
+         sprintf(name, "r.%d", csa->count);
+         glp_set_row_name(csa->P, i, name);
+      }
+      /* parse linear form */
+      len = parse_linear_form(csa);
+      glp_set_mat_row(csa->P, i, len, csa->ind, csa->val);
+      /* parse constraint sense */
+      if (csa->token == T_LE)
+         type = GLP_UP, scan_token(csa);
+      else if (csa->token == T_GE)
+         type = GLP_LO, scan_token(csa);
+      else if (csa->token == T_EQ)
+         type = GLP_FX, scan_token(csa);
+      else
+         error(csa, "missing constraint sense\n");
+      /* parse right-hand side */
+      if (csa->token == T_PLUS)
+         s = +1.0, scan_token(csa);
+      else if (csa->token == T_MINUS)
+         s = -1.0, scan_token(csa);
+      else
+         s = +1.0;
+      if (csa->token != T_NUMBER)
+         error(csa, "missing right-hand side\n");
+      glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value);
+      /* the rest of the current line must be empty */
+      if (!(csa->c == '\n' || csa->c == XEOF))
+         error(csa, "invalid symbol(s) beyond right-hand side\n");
+      scan_token(csa);
+      /* if the next token is a sign, numeric constant, or a symbolic
+         name, here is another constraint */
+      if (csa->token == T_PLUS || csa->token == T_MINUS ||
+          csa->token == T_NUMBER || csa->token == T_NAME) goto loop;
+      return;
+}
+
+static void set_lower_bound(struct csa *csa, int j, double lb)
+{     /* set lower bound of j-th variable */
+      if (csa->lb[j] != +DBL_MAX)
+      {  warning(csa, "lower bound of variable `%s' redefined\n",
+            glp_get_col_name(csa->P, j));
+      }
+      csa->lb[j] = lb;
+      return;
+}
+
+static void set_upper_bound(struct csa *csa, int j, double ub)
+{     /* set upper bound of j-th variable */
+      if (csa->ub[j] != -DBL_MAX)
+      {  warning(csa, "upper bound of variable `%s' redefined\n",
+            glp_get_col_name(csa->P, j));
+      }
+      csa->ub[j] = ub;
+      return;
+}
+
+/***********************************************************************
+*  parse_bounds - parse bounds section
+*
+*  This routine parses the bounds section using the following syntax:
+*
+*  <variable> ::= <symbolic name>
+*  <infinity> ::= infinity | inf
+*  <bound> ::= <numeric constant> | + <numeric constant> |
+*     - <numeric constant> | + <infinity> | - <infinity>
+*  <lt> ::= < | <= | =<
+*  <gt> ::= > | >= | =>
+*  <bound definition> ::= <bound> <lt> <variable> <lt> <bound> |
+*     <bound> <lt> <variable> | <variable> <lt> <bound> |
+*     <variable> <gt> <bound> | <variable> = <bound> | <variable> free
+*  <bounds> ::= bounds | bound
+*  <bounds section> ::= <bounds> |
+*     <bounds section> <bound definition> */
+
+static void parse_bounds(struct csa *csa)
+{     int j, lb_flag;
+      double lb, s;
+      /* parse the keyword 'bounds' */
+      xassert(csa->token == T_BOUNDS);
+      scan_token(csa);
+loop: /* bound definition can start with a sign, numeric constant, or
+         a symbolic name */
+      if (!(csa->token == T_PLUS || csa->token == T_MINUS ||
+            csa->token == T_NUMBER || csa->token == T_NAME)) goto done;
+      /* parse bound definition */
+      if (csa->token == T_PLUS || csa->token == T_MINUS)
+      {  /* parse signed lower bound */
+         lb_flag = 1;
+         s = (csa->token == T_PLUS ? +1.0 : -1.0);
+         scan_token(csa);
+         if (csa->token == T_NUMBER)
+            lb = s * csa->value, scan_token(csa);
+         else if (the_same(csa->image, "infinity") ||
+                  the_same(csa->image, "inf"))
+         {  if (s > 0.0)
+               error(csa, "invalid use of `+inf' as lower bound\n");
+            lb = -DBL_MAX, scan_token(csa);
+         }
+         else
+            error(csa, "missing lower bound\n");
+      }
+      else if (csa->token == T_NUMBER)
+      {  /* parse unsigned lower bound */
+         lb_flag = 1;
+         lb = csa->value, scan_token(csa);
+      }
+      else
+      {  /* lower bound is not specified */
+         lb_flag = 0;
+      }
+      /* parse the token that should follow the lower bound */
+      if (lb_flag)
+      {  if (csa->token != T_LE)
+            error(csa, "missing `<', `<=', or `=<' after lower bound\n")
+               ;
+         scan_token(csa);
+      }
+      /* parse variable name */
+      if (csa->token != T_NAME)
+         error(csa, "missing variable name\n");
+      j = find_col(csa, csa->image);
+      /* set lower bound */
+      if (lb_flag) set_lower_bound(csa, j, lb);
+      scan_token(csa);
+      /* parse the context that follows the variable name */
+      if (csa->token == T_LE)
+      {  /* parse upper bound */
+         scan_token(csa);
+         if (csa->token == T_PLUS || csa->token == T_MINUS)
+         {  /* parse signed upper bound */
+            s = (csa->token == T_PLUS ? +1.0 : -1.0);
+            scan_token(csa);
+            if (csa->token == T_NUMBER)
+            {  set_upper_bound(csa, j, s * csa->value);
+               scan_token(csa);
+            }
+            else if (the_same(csa->image, "infinity") ||
+                     the_same(csa->image, "inf"))
+            {  if (s < 0.0)
+                  error(csa, "invalid use of `-inf' as upper bound\n");
+               set_upper_bound(csa, j, +DBL_MAX);
+               scan_token(csa);
+            }
+            else
+               error(csa, "missing upper bound\n");
+         }
+         else if (csa->token == T_NUMBER)
+         {  /* parse unsigned upper bound */
+            set_upper_bound(csa, j, csa->value);
+            scan_token(csa);
+         }
+         else
+            error(csa, "missing upper bound\n");
+      }
+      else if (csa->token == T_GE)
+      {  /* parse lower bound */
+         if (lb_flag)
+         {  /* the context '... <= x >= ...' is invalid */
+            error(csa, "invalid bound definition\n");
+         }
+         scan_token(csa);
+         if (csa->token == T_PLUS || csa->token == T_MINUS)
+         {  /* parse signed lower bound */
+            s = (csa->token == T_PLUS ? +1.0 : -1.0);
+            scan_token(csa);
+            if (csa->token == T_NUMBER)
+            {  set_lower_bound(csa, j, s * csa->value);
+               scan_token(csa);
+            }
+            else if (the_same(csa->image, "infinity") ||
+                     the_same(csa->image, "inf") == 0)
+            {  if (s > 0.0)
+                  error(csa, "invalid use of `+inf' as lower bound\n");
+               set_lower_bound(csa, j, -DBL_MAX);
+               scan_token(csa);
+            }
+            else
+               error(csa, "missing lower bound\n");
+         }
+         else if (csa->token == T_NUMBER)
+         {  /* parse unsigned lower bound */
+            set_lower_bound(csa, j, csa->value);
+            scan_token(csa);
+         }
+         else
+            error(csa, "missing lower bound\n");
+      }
+      else if (csa->token == T_EQ)
+      {  /* parse fixed value */
+         if (lb_flag)
+         {  /* the context '... <= x = ...' is invalid */
+            error(csa, "invalid bound definition\n");
+         }
+         scan_token(csa);
+         if (csa->token == T_PLUS || csa->token == T_MINUS)
+         {  /* parse signed fixed value */
+            s = (csa->token == T_PLUS ? +1.0 : -1.0);
+            scan_token(csa);
+            if (csa->token == T_NUMBER)
+            {  set_lower_bound(csa, j, s * csa->value);
+               set_upper_bound(csa, j, s * csa->value);
+               scan_token(csa);
+            }
+            else
+               error(csa, "missing fixed value\n");
+         }
+         else if (csa->token == T_NUMBER)
+         {  /* parse unsigned fixed value */
+            set_lower_bound(csa, j, csa->value);
+            set_upper_bound(csa, j, csa->value);
+            scan_token(csa);
+         }
+         else
+            error(csa, "missing fixed value\n");
+      }
+      else if (the_same(csa->image, "free"))
+      {  /* parse the keyword 'free' */
+         if (lb_flag)
+         {  /* the context '... <= x free ...' is invalid */
+            error(csa, "invalid bound definition\n");
+         }
+         set_lower_bound(csa, j, -DBL_MAX);
+         set_upper_bound(csa, j, +DBL_MAX);
+         scan_token(csa);
+      }
+      else if (!lb_flag)
+      {  /* neither lower nor upper bounds are specified */
+         error(csa, "invalid bound definition\n");
+      }
+      goto loop;
+done: return;
+}
+
+/***********************************************************************
+*  parse_integer - parse general, integer, or binary section
+*
+*  <variable> ::= <symbolic name>
+*  <general> ::= general | generals | gen
+*  <integer> ::= integer | integers | int
+*  <binary> ::= binary | binaries | bin
+*  <section head> ::= <general> <integer> <binary>
+*  <additional section> ::= <section head> |
+*     <additional section> <variable> */
+
+static void parse_integer(struct csa *csa)
+{     int j, binary;
+      /* parse the keyword 'general', 'integer', or 'binary' */
+      if (csa->token == T_GENERAL)
+         binary = 0, scan_token(csa);
+      else if (csa->token == T_INTEGER)
+         binary = 0, scan_token(csa);
+      else if (csa->token == T_BINARY)
+         binary = 1, scan_token(csa);
+      else
+         xassert(csa != csa);
+      /* parse list of variables (may be empty) */
+      while (csa->token == T_NAME)
+      {  /* find the corresponding column */
+         j = find_col(csa, csa->image);
+         /* change kind of the variable */
+         glp_set_col_kind(csa->P, j, GLP_IV);
+         /* set 0-1 bounds for the binary variable */
+         if (binary)
+         {  set_lower_bound(csa, j, 0.0);
+            set_upper_bound(csa, j, 1.0);
+         }
+         scan_token(csa);
+      }
+      return;
+}
+
+int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
+{     /* read problem data in CPLEX LP format */
+      glp_cpxcp _parm;
+      struct csa _csa, *csa = &_csa;
+      int ret;
+      xprintf("Reading problem data from `%s'...\n", fname);
+      if (parm == NULL)
+         glp_init_cpxcp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_read_lp", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->parm = parm;
+      csa->fname = fname;
+      csa->fp = NULL;
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->count = 0;
+      csa->c = '\n';
+      csa->token = T_EOF;
+      csa->image[0] = '\0';
+      csa->imlen = 0;
+      csa->value = 0.0;
+      csa->n_max = 100;
+      csa->ind = xcalloc(1+csa->n_max, sizeof(int));
+      csa->val = xcalloc(1+csa->n_max, sizeof(double));
+      csa->flag = xcalloc(1+csa->n_max, sizeof(char));
+      memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
+      csa->lb = xcalloc(1+csa->n_max, sizeof(double));
+      csa->ub = xcalloc(1+csa->n_max, sizeof(double));
+      /* erase problem object */
+      glp_erase_prob(P);
+      glp_create_index(P);
+      /* open input CPLEX LP file */
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* scan very first token */
+      scan_token(csa);
+      /* parse definition of the objective function */
+      if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE))
+         error(csa, "`minimize' or `maximize' keyword missing\n");
+      parse_objective(csa);
+      /* parse constraints section */
+      if (csa->token != T_SUBJECT_TO)
+         error(csa, "constraints section missing\n");
+      parse_constraints(csa);
+      /* parse optional bounds section */
+      if (csa->token == T_BOUNDS) parse_bounds(csa);
+      /* parse optional general, integer, and binary sections */
+      while (csa->token == T_GENERAL ||
+             csa->token == T_INTEGER ||
+             csa->token == T_BINARY) parse_integer(csa);
+      /* check for the keyword 'end' */
+      if (csa->token == T_END)
+         scan_token(csa);
+      else if (csa->token == T_EOF)
+         warning(csa, "keyword `end' missing\n");
+      else
+         error(csa, "symbol `%s' in wrong position\n", csa->image);
+      /* nothing must follow the keyword 'end' (except comments) */
+      if (csa->token != T_EOF)
+         error(csa, "extra symbol(s) detected beyond `end'\n");
+      /* set bounds of variables */
+      {  int j, type;
+         double lb, ub;
+         for (j = 1; j <= P->n; j++)
+         {  lb = csa->lb[j];
+            ub = csa->ub[j];
+            if (lb == +DBL_MAX) lb = 0.0;      /* default lb */
+            if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */
+            if (lb == -DBL_MAX && ub == +DBL_MAX)
+               type = GLP_FR;
+            else if (ub == +DBL_MAX)
+               type = GLP_LO;
+            else if (lb == -DBL_MAX)
+               type = GLP_UP;
+            else if (lb != ub)
+               type = GLP_DB;
+            else
+               type = GLP_FX;
+            glp_set_col_bnds(csa->P, j, type, lb, ub);
+         }
+      }
+      /* print some statistics */
+      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+         P->nnz, P->nnz == 1 ? "" : "s");
+      if (glp_get_num_int(P) > 0)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         if (ni == 1)
+         {  if (nb == 0)
+               xprintf("One variable is integer\n");
+            else
+               xprintf("One variable is binary\n");
+         }
+         else
+         {  xprintf("%d integer variables, ", ni);
+            if (nb == 0)
+               xprintf("none");
+            else if (nb == 1)
+               xprintf("one");
+            else if (nb == ni)
+               xprintf("all");
+            else
+               xprintf("%d", nb);
+            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+         }
+      }
+      xprintf("%d lines were read\n", csa->count);
+      /* problem data has been successfully read */
+      glp_delete_index(P);
+      glp_sort_matrix(P);
+      ret = 0;
+done: if (csa->fp != NULL) xfclose(csa->fp);
+      xfree(csa->ind);
+      xfree(csa->val);
+      xfree(csa->flag);
+      xfree(csa->lb);
+      xfree(csa->ub);
+      if (ret != 0) glp_erase_prob(P);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_lp - write problem data in CPLEX LP format
+*
+*  SYNOPSIS
+*
+*  int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char
+*     *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_lp writes problem data in CPLEX LP format to
+*  a text file.
+*
+*  The parameter parm is a pointer to the structure glp_cpxcp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  written.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_write_lp returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+#define csa csa1
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* pointer to problem object */
+      const glp_cpxcp *parm;
+      /* pointer to control parameters */
+};
+
+static int check_name(char *name)
+{     /* check if specified name is valid for CPLEX LP format */
+      if (*name == '.') return 1;
+      if (isdigit((unsigned char)*name)) return 1;
+      for (; *name; name++)
+      {  if (!isalnum((unsigned char)*name) &&
+             strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1;
+      }
+      return 0; /* name is ok */
+}
+
+static void adjust_name(char *name)
+{     /* attempt to adjust specified name to make it valid for CPLEX LP
+         format */
+      for (; *name; name++)
+      {  if (*name == ' ')
+            *name = '_';
+         else if (*name == '-')
+            *name = '~';
+         else if (*name == '[')
+            *name = '(';
+         else if (*name == ']')
+            *name = ')';
+      }
+      return;
+}
+
+static char *row_name(struct csa *csa, int i, char rname[255+1])
+{     /* construct symbolic name of i-th row (constraint) */
+      const char *name;
+      if (i == 0)
+         name = glp_get_obj_name(csa->P);
+      else
+         name = glp_get_row_name(csa->P, i);
+      if (name == NULL) goto fake;
+      strcpy(rname, name);
+      adjust_name(rname);
+      if (check_name(rname)) goto fake;
+      return rname;
+fake: if (i == 0)
+         strcpy(rname, "obj");
+      else
+         sprintf(rname, "r_%d", i);
+      return rname;
+}
+
+static char *col_name(struct csa *csa, int j, char cname[255+1])
+{     /* construct symbolic name of j-th column (variable) */
+      const char *name;
+      name = glp_get_col_name(csa->P, j);
+      if (name == NULL) goto fake;
+      strcpy(cname, name);
+      adjust_name(cname);
+      if (check_name(cname)) goto fake;
+      return cname;
+fake: sprintf(cname, "x_%d", j);
+      return cname;
+}
+
+int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
+{     /* write problem data in CPLEX LP format */
+      glp_cpxcp _parm;
+      struct csa _csa, *csa = &_csa;
+      XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, len, flag, count, ret;
+      char line[1000+1], term[500+1], name[255+1];
+      xprintf("Writing problem data to `%s'...\n", fname);
+      if (parm == NULL)
+         glp_init_cpxcp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_write_lp", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->parm = parm;
+      /* create output CPLEX LP file */
+      fp = xfopen(fname, "w"), count = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* write problem name */
+      xfprintf(fp, "\\* Problem: %s *\\\n",
+         P->name == NULL ? "Unknown" : P->name), count++;
+      xfprintf(fp, "\n"), count++;
+      /* the problem should contain at least one row and one column */
+      if (!(P->m > 0 && P->n > 0))
+      {  xprintf("Warning: problem has no rows/columns\n");
+         xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"),
+            count++;
+         xfprintf(fp, "\n"), count++;
+         goto skip;
+      }
+      /* write the objective function definition */
+      if (P->dir == GLP_MIN)
+         xfprintf(fp, "Minimize\n"), count++;
+      else if (P->dir == GLP_MAX)
+         xfprintf(fp, "Maximize\n"), count++;
+      else
+         xassert(P != P);
+      row_name(csa, 0, name);
+      sprintf(line, " %s:", name);
+      len = 0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->coef != 0.0 || col->ptr == NULL)
+         {  len++;
+            col_name(csa, j, name);
+            if (col->coef == 0.0)
+               sprintf(term, " + 0 %s", name); /* empty column */
+            else if (col->coef == +1.0)
+               sprintf(term, " + %s", name);
+            else if (col->coef == -1.0)
+               sprintf(term, " - %s", name);
+            else if (col->coef > 0.0)
+               sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name);
+            else
+               sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name);
+            if (strlen(line) + strlen(term) > 72)
+               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+            strcat(line, term);
+         }
+      }
+      if (len == 0)
+      {  /* empty objective */
+         sprintf(term, " 0 %s", col_name(csa, 1, name));
+         strcat(line, term);
+      }
+      xfprintf(fp, "%s\n", line), count++;
+      if (P->c0 != 0.0)
+         xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0),
+            count++;
+      xfprintf(fp, "\n"), count++;
+      /* write the constraints section */
+      xfprintf(fp, "Subject To\n"), count++;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type == GLP_FR) continue; /* skip free row */
+         row_name(csa, i, name);
+         sprintf(line, " %s:", name);
+         /* linear form */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  col_name(csa, aij->col->j, name);
+            if (aij->val == +1.0)
+               sprintf(term, " + %s", name);
+            else if (aij->val == -1.0)
+               sprintf(term, " - %s", name);
+            else if (aij->val > 0.0)
+               sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name);
+            else
+               sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name);
+            if (strlen(line) + strlen(term) > 72)
+               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+            strcat(line, term);
+         }
+         if (row->type == GLP_DB)
+         {  /* double-bounded (ranged) constraint */
+            sprintf(term, " - ~r_%d", i);
+            if (strlen(line) + strlen(term) > 72)
+               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+            strcat(line, term);
+         }
+         else if (row->ptr == NULL)
+         {  /* empty constraint */
+            sprintf(term, " 0 %s", col_name(csa, 1, name));
+            strcat(line, term);
+         }
+         /* right hand-side */
+         if (row->type == GLP_LO)
+            sprintf(term, " >= %.*g", DBL_DIG, row->lb);
+         else if (row->type == GLP_UP)
+            sprintf(term, " <= %.*g", DBL_DIG, row->ub);
+         else if (row->type == GLP_DB || row->type == GLP_FX)
+            sprintf(term, " = %.*g", DBL_DIG, row->lb);
+         else
+            xassert(row != row);
+         if (strlen(line) + strlen(term) > 72)
+            xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
+         strcat(line, term);
+         xfprintf(fp, "%s\n", line), count++;
+      }
+      xfprintf(fp, "\n"), count++;
+      /* write the bounds section */
+      flag = 0;
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type != GLP_DB) continue;
+         if (!flag)
+            xfprintf(fp, "Bounds\n"), flag = 1, count++;
+         xfprintf(fp, " 0 <= ~r_%d <= %.*g\n",
+            i, DBL_DIG, row->ub - row->lb), count++;
+      }
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->type == GLP_LO && col->lb == 0.0) continue;
+         if (!flag)
+            xfprintf(fp, "Bounds\n"), flag = 1, count++;
+         col_name(csa, j, name);
+         if (col->type == GLP_FR)
+            xfprintf(fp, " %s free\n", name), count++;
+         else if (col->type == GLP_LO)
+            xfprintf(fp, " %s >= %.*g\n",
+               name, DBL_DIG, col->lb), count++;
+         else if (col->type == GLP_UP)
+            xfprintf(fp, " -Inf <= %s <= %.*g\n",
+               name, DBL_DIG, col->ub), count++;
+         else if (col->type == GLP_DB)
+            xfprintf(fp, " %.*g <= %s <= %.*g\n",
+               DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++;
+         else if (col->type == GLP_FX)
+            xfprintf(fp, " %s = %.*g\n",
+               name, DBL_DIG, col->lb), count++;
+         else
+            xassert(col != col);
+      }
+      if (flag) xfprintf(fp, "\n"), count++;
+      /* write the integer section */
+      flag = 0;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->kind == GLP_CV) continue;
+         xassert(col->kind == GLP_IV);
+         if (!flag)
+            xfprintf(fp, "Generals\n"), flag = 1, count++;
+         xfprintf(fp, " %s\n", col_name(csa, j, name)), count++;
+      }
+      if (flag) xfprintf(fp, "\n"), count++;
+skip: /* write the end keyword */
+      xfprintf(fp, "End\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* problem data has been successfully written */
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpdmp.c
===================================================================
--- deps/glpk/src/glpdmp.c	(revision 9)
+++ deps/glpk/src/glpdmp.c	(revision 9)
@@ -0,0 +1,259 @@
+/* glpdmp.c (dynamic memory pool) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpdmp.h"
+
+#if 1 /* 29/VIII-2008 */
+/* some processors need data to be properly aligned; the macro
+   align_datasize enlarges the specified size of a data item to provide
+   a proper alignment of immediately following data */
+
+#define align_datasize(size) ((((size) + 7) / 8) * 8)
+/* 8 bytes is sufficient in both 32- and 64-bit environments */
+#endif
+
+#ifdef GLP_DEBUG
+struct info
+{     DMP *pool;
+      int size;
+};
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_create_pool - create dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  DMP *dmp_create_pool(void);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_create_pool creates a dynamic memory pool.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the memory pool created. */
+
+DMP *dmp_create_pool(void)
+{     DMP *pool;
+      int k;
+#ifdef GLP_DEBUG
+      xprintf("dmp_create_pool: warning: debug mode enabled\n");
+#endif
+      pool = xmalloc(sizeof(DMP));
+#if 0
+      pool->size = 0;
+#endif
+      for (k = 0; k <= 31; k++) pool->avail[k] = NULL;
+      pool->block = NULL;
+      pool->used = DMP_BLK_SIZE;
+      pool->count.lo = pool->count.hi = 0;
+      return pool;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_get_atom - get free atom from dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  void *dmp_get_atom(DMP *pool, int size);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_get_atom obtains a free atom (memory block) from the
+*  specified memory pool.
+*
+*  The parameter size is the atom size, in bytes, 1 <= size <= 256.
+*
+*  Note that the free atom contains arbitrary data, not binary zeros.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the free atom obtained. */
+
+void *dmp_get_atom(DMP *pool, int size)
+{     void *atom;
+      int k;
+#ifdef GLP_DEBUG
+      int orig_size = size;
+#endif
+      if (!(1 <= size && size <= 256))
+         xerror("dmp_get_atom: size = %d; invalid atom size\n", size);
+#if 0
+      if (!(pool->size == 0 || pool->size == size))
+         xerror("dmp_get_atom: size = %d; wrong atom size\n", size);
+#endif
+      /* adjust the size to provide the proper data alignment */
+      size = align_datasize(size);
+#ifdef GLP_DEBUG
+      size += align_datasize(sizeof(struct info));
+#endif
+      /* adjust the size to make it multiple of 8 bytes, if needed */
+      size = ((size + 7) / 8) * 8;
+      /* determine the corresponding list of free cells */
+      k = size / 8 - 1;
+      xassert(0 <= k && k <= 31);
+      /* obtain a free atom */
+      if (pool->avail[k] == NULL)
+      {  /* the list of free cells is empty */
+         if (pool->used + size > DMP_BLK_SIZE)
+         {  /* allocate a new memory block */
+            void *block = xmalloc(DMP_BLK_SIZE);
+            *(void **)block = pool->block;
+            pool->block = block;
+            pool->used = align_datasize(sizeof(void *));
+         }
+         /* place the atom in the current memory block */
+         atom = (char *)pool->block + pool->used;
+         pool->used += size;
+      }
+      else
+      {  /* obtain the atom from the list of free cells */
+         atom = pool->avail[k];
+         pool->avail[k] = *(void **)atom;
+      }
+      memset(atom, '?', size);
+      /* increase the number of atoms which are currently in use */
+      pool->count.lo++;
+      if (pool->count.lo == 0) pool->count.hi++;
+#ifdef GLP_DEBUG
+      ((struct info *)atom)->pool = pool;
+      ((struct info *)atom)->size = orig_size;
+      atom = (char *)atom + align_datasize(sizeof(struct info));
+#endif
+      return atom;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_free_atom - return atom to dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  void dmp_free_atom(DMP *pool, void *atom, int size);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_free_atom returns the specified atom (memory block)
+*  to the specified memory pool, making it free.
+*
+*  The parameter size is the atom size, in bytes, 1 <= size <= 256.
+*
+*  Note that the atom can be returned only to the pool, from which it
+*  was obtained, and its size must be exactly the same as on obtaining
+*  it from the pool. */
+
+void dmp_free_atom(DMP *pool, void *atom, int size)
+{     int k;
+      if (!(1 <= size && size <= 256))
+         xerror("dmp_free_atom: size = %d; invalid atom size\n", size);
+#if 0
+      if (!(pool->size == 0 || pool->size == size))
+         xerror("dmp_free_atom: size = %d; wrong atom size\n", size);
+#endif
+      if (pool->count.lo == 0 && pool->count.hi == 0)
+         xerror("dmp_free_atom: pool allocation error\n");
+#ifdef GLP_DEBUG
+      atom = (char *)atom - align_datasize(sizeof(struct info));
+      xassert(((struct info *)atom)->pool == pool);
+      xassert(((struct info *)atom)->size == size);
+#endif
+      /* adjust the size to provide the proper data alignment */
+      size = align_datasize(size);
+#ifdef GLP_DEBUG
+      size += align_datasize(sizeof(struct info));
+#endif
+      /* adjust the size to make it multiple of 8 bytes, if needed */
+      size = ((size + 7) / 8) * 8;
+      /* determine the corresponding list of free cells */
+      k = size / 8 - 1;
+      xassert(0 <= k && k <= 31);
+      /* return the atom to the list of free cells */
+      *(void **)atom = pool->avail[k];
+      pool->avail[k] = atom;
+      /* decrease the number of atoms which are currently in use */
+      pool->count.lo--;
+      if (pool->count.lo == 0xFFFFFFFF) pool->count.hi--;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_in_use - determine how many atoms are still in use
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  glp_long dmp_in_use(DMP *pool);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_in_use determines how many atoms allocated from the
+*  specified memory pool with the routine dmp_get_atom are still in use,
+*  i.e. not returned to the pool with the routine dmp_free_atom.
+*
+*  RETURNS
+*
+*  The routine returns the number of atoms which are still in use. */
+
+glp_long dmp_in_use(DMP *pool)
+{     return
+         pool->count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  dmp_delete_pool - delete dynamic memory pool
+*
+*  SYNOPSIS
+*
+*  #include "glpdmp.h"
+*  void dmp_delete_pool(DMP *pool);
+*
+*  DESCRIPTION
+*
+*  The routine dmp_delete_pool deletes the specified dynamic memory
+*  pool and frees all the memory allocated to this object. */
+
+void dmp_delete_pool(DMP *pool)
+{     while (pool->block != NULL)
+      {  void *block = pool->block;
+         pool->block = *(void **)block;
+         xfree(block);
+      }
+      xfree(pool);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpdmp.h
===================================================================
--- deps/glpk/src/glpdmp.h	(revision 9)
+++ deps/glpk/src/glpdmp.h	(revision 9)
@@ -0,0 +1,80 @@
+/* glpdmp.h (dynamic memory pool) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPDMP_H
+#define GLPDMP_H
+
+#include "glpenv.h"
+
+typedef struct DMP DMP;
+
+#define DMP_BLK_SIZE 8000
+/* size of memory blocks, in bytes, allocated for memory pools */
+
+struct DMP
+{     /* dynamic memory pool */
+#if 0
+      int size;
+      /* size of atoms, in bytes, 1 <= size <= 256; if size = 0, atoms
+         may have different sizes */
+#endif
+      void *avail[32];
+      /* avail[k], 0 <= k <= 31, is a pointer to the first available
+         (free) cell of (k+1)*8 bytes long; in the beginning of each
+         free cell there is a pointer to another free cell of the same
+         length */
+      void *block;
+      /* pointer to the most recently allocated memory block; in the
+         beginning of each allocated memory block there is a pointer to
+         the previously allocated memory block */
+      int used;
+      /* number of bytes used in the most recently allocated memory
+         block */
+      glp_long count;
+      /* number of atoms which are currently in use */
+};
+
+#define dmp_create_pool _glp_dmp_create_pool
+DMP *dmp_create_pool(void);
+/* create dynamic memory pool */
+
+#define dmp_get_atom _glp_dmp_get_atom
+void *dmp_get_atom(DMP *pool, int size);
+/* get free atom from dynamic memory pool */
+
+#define dmp_free_atom _glp_dmp_free_atom
+void dmp_free_atom(DMP *pool, void *atom, int size);
+/* return atom to dynamic memory pool */
+
+#define dmp_in_use _glp_dmp_in_use
+glp_long dmp_in_use(DMP *pool);
+/* determine how many atoms are still in use */
+
+#define dmp_delete_pool _glp_dmp_delete_pool
+void dmp_delete_pool(DMP *pool);
+/* delete dynamic memory pool */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpdmx.c
===================================================================
--- deps/glpk/src/glpdmx.c	(revision 9)
+++ deps/glpk/src/glpdmx.c	(revision 9)
@@ -0,0 +1,1678 @@
+/* glpdmx.c (reading/writing data in DIMACS format) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_STDIO
+#include "glpapi.h"
+
+struct csa
+{     /* common storage area */
+      jmp_buf jump;
+      /* label for go to in case of error */
+      const char *fname;
+      /* name of input text file */
+      XFILE *fp;
+      /* stream assigned to input text file */
+      int count;
+      /* line count */
+      int c;
+      /* current character */
+      char field[255+1];
+      /* data field */
+      int empty;
+      /* warning 'empty line ignored' was printed */
+      int nonint;
+      /* warning 'non-integer data detected' was printed */
+};
+
+static void error(struct csa *csa, const char *fmt, ...)
+{     /* print error message and terminate processing */
+      va_list arg;
+      xprintf("%s:%d: error: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      xprintf("\n");
+      longjmp(csa->jump, 1);
+      /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{     /* print warning message and continue processing */
+      va_list arg;
+      xprintf("%s:%d: warning: ", csa->fname, csa->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      xprintf("\n");
+      return;
+}
+
+static void read_char(struct csa *csa)
+{     /* read character from input text file */
+      int c;
+      if (csa->c == '\n') csa->count++;
+      c = xfgetc(csa->fp);
+      if (c < 0)
+      {  if (xferror(csa->fp))
+            error(csa, "read error - %s", xerrmsg());
+         else if (csa->c == '\n')
+            error(csa, "unexpected end of file");
+         else
+         {  warning(csa, "missing final end of line");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+         error(csa, "invalid control character 0x%02X", c);
+      csa->c = c;
+      return;
+}
+
+static void read_designator(struct csa *csa)
+{     /* read one-character line designator */
+      xassert(csa->c == '\n');
+      read_char(csa);
+      for (;;)
+      {  /* skip preceding white-space characters */
+         while (csa->c == ' ')
+            read_char(csa);
+         if (csa->c == '\n')
+         {  /* ignore empty line */
+            if (!csa->empty)
+            {  warning(csa, "empty line ignored");
+               csa->empty = 1;
+            }
+            read_char(csa);
+         }
+         else if (csa->c == 'c')
+         {  /* skip comment line */
+            while (csa->c != '\n')
+               read_char(csa);
+            read_char(csa);
+         }
+         else
+         {  /* hmm... looks like a line designator */
+            csa->field[0] = (char)csa->c, csa->field[1] = '\0';
+            /* check that it is followed by a white-space character */
+            read_char(csa);
+            if (!(csa->c == ' ' || csa->c == '\n'))
+               error(csa, "line designator missing or invalid");
+            break;
+         }
+      }
+      return;
+}
+
+static void read_field(struct csa *csa)
+{     /* read data field */
+      int len = 0;
+      /* skip preceding white-space characters */
+      while (csa->c == ' ')
+         read_char(csa);
+      /* scan data field */
+      if (csa->c == '\n')
+         error(csa, "unexpected end of line");
+      while (!(csa->c == ' ' || csa->c == '\n'))
+      {  if (len == sizeof(csa->field)-1)
+            error(csa, "data field `%.15s...' too long", csa->field);
+         csa->field[len++] = (char)csa->c;
+         read_char(csa);
+      }
+      csa->field[len] = '\0';
+      return;
+}
+
+static void end_of_line(struct csa *csa)
+{     /* skip white-space characters until end of line */
+      while (csa->c == ' ')
+         read_char(csa);
+      if (csa->c != '\n')
+         error(csa, "too many data fields specified");
+      return;
+}
+
+static void check_int(struct csa *csa, double num)
+{     /* print a warning if non-integer data are detected */
+      if (!csa->nonint && num != floor(num))
+      {  warning(csa, "non-integer data detected");
+         csa->nonint = 1;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_mincost - read min-cost flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+*     int a_cost, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_mincost reads minimum cost flow problem data in
+*  DIMACS format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, j, k, nv, na, ret = 0;
+      double rhs, low, cap, cost;
+      char *flag = NULL;
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_read_mincost: v_rhs = %d; invalid offset\n",
+            v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_read_mincost: a_low = %d; invalid offset\n",
+            a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_read_mincost: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_read_mincost: a_cost = %d; invalid offset\n",
+            a_cost);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading min-cost flow problem data from `%s'...\n",
+         fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "min") != 0)
+         error(csa, "wrong problem designator; `min' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+         error(csa, "number of nodes missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &na) == 0 && na >= 0))
+         error(csa, "number of arcs missing or invalid");
+      xprintf("Flow network has %d node%s and %d arc%s\n",
+         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      flag = xcalloc(1+nv, sizeof(char));
+      memset(&flag[1], 0, nv * sizeof(char));
+      if (v_rhs >= 0)
+      {  rhs = 0.0;
+         for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
+         }
+      }
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "node number %d out of range", i);
+         if (flag[i])
+            error(csa, "duplicate descriptor of node %d", i);
+         read_field(csa);
+         if (str2num(csa->field, &rhs) != 0)
+            error(csa, "node supply/demand missing or invalid");
+         check_int(csa, rhs);
+         if (v_rhs >= 0)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_rhs, &rhs, sizeof(double));
+         }
+         flag[i] = 1;
+         end_of_line(csa);
+      }
+      xfree(flag), flag = NULL;
+      /* read arc descriptor lines */
+      for (k = 1; k <= na; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "a") != 0)
+            error(csa, "wrong line designator; `a' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "starting node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "starting node number %d out of range", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "ending node number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "ending node number %d out of range", j);
+         read_field(csa);
+         if (!(str2num(csa->field, &low) == 0 && low >= 0.0))
+            error(csa, "lower bound of arc flow missing or invalid");
+         check_int(csa, low);
+         read_field(csa);
+         if (!(str2num(csa->field, &cap) == 0 && cap >= low))
+            error(csa, "upper bound of arc flow missing or invalid");
+         check_int(csa, cap);
+         read_field(csa);
+         if (str2num(csa->field, &cost) != 0)
+            error(csa, "per-unit cost of arc flow missing or invalid");
+         check_int(csa, cost);
+         a = glp_add_arc(G, i, j);
+         if (a_low >= 0)
+            memcpy((char *)a->data + a_low, &low, sizeof(double));
+         if (a_cap >= 0)
+            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
+         if (a_cost >= 0)
+            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_mincost - write min-cost flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+*     int a_cost, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_mincost writes minimum cost flow problem data
+*  in DIMACS format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, count = 0, ret;
+      double rhs, low, cap, cost;
+      if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+         xerror("glp_write_mincost: v_rhs = %d; invalid offset\n",
+            v_rhs);
+      if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_low = %d; invalid offset\n",
+            a_low);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
+            a_cap);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_cost = %d; invalid offset\n",
+            a_cost);
+      xprintf("Writing min-cost flow problem data to `%s'...\n",
+         fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++;
+      if (v_rhs >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double));
+            if (rhs != 0.0)
+               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++;
+         }
+      }
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  if (a_low >= 0)
+               memcpy(&low, (char *)a->data + a_low, sizeof(double));
+            else
+               low = 0.0;
+            if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 0.0;
+            xfprintf(fp, "a %d %d %.*g %.*g %.*g\n",
+               a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap,
+               DBL_DIG, cost), count++;
+         }
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_maxflow - read maximum flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_maxflow reads maximum flow problem data in
+*  DIMACS format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap,
+      const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_arc *a;
+      int i, j, k, s, t, nv, na, ret = 0;
+      double cap;
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_read_maxflow: a_cap = %d; invalid offset\n",
+            a_cap);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading maximum flow problem data from `%s'...\n",
+         fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "max") != 0)
+         error(csa, "wrong problem designator; `max' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 2))
+         error(csa, "number of nodes missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &na) == 0 && na >= 0))
+         error(csa, "number of arcs missing or invalid");
+      xprintf("Flow network has %d node%s and %d arc%s\n",
+         nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      s = t = 0;
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "node number %d out of range", i);
+         read_field(csa);
+         if (strcmp(csa->field, "s") == 0)
+         {  if (s > 0)
+               error(csa, "only one source node allowed");
+            s = i;
+         }
+         else if (strcmp(csa->field, "t") == 0)
+         {  if (t > 0)
+               error(csa, "only one sink node allowed");
+            t = i;
+         }
+         else
+            error(csa, "wrong node designator; `s' or `t' expected");
+         if (s > 0 && s == t)
+            error(csa, "source and sink nodes must be distinct");
+         end_of_line(csa);
+      }
+      if (s == 0)
+         error(csa, "source node descriptor missing\n");
+      if (t == 0)
+         error(csa, "sink node descriptor missing\n");
+      if (_s != NULL) *_s = s;
+      if (_t != NULL) *_t = t;
+      /* read arc descriptor lines */
+      for (k = 1; k <= na; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "a") != 0)
+            error(csa, "wrong line designator; `a' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "starting node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "starting node number %d out of range", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "ending node number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "ending node number %d out of range", j);
+         read_field(csa);
+         if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0))
+            error(csa, "arc capacity missing or invalid");
+         check_int(csa, cap);
+         a = glp_add_arc(G, i, j);
+         if (a_cap >= 0)
+            memcpy((char *)a->data + a_cap, &cap, sizeof(double));
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_maxflow - write maximum flow problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_maxflow writes maximum flow problem data in
+*  DIMACS format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+      const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, count = 0, ret;
+      double cap;
+      if (!(1 <= s && s <= G->nv))
+         xerror("glp_write_maxflow: s = %d; source node number out of r"
+            "ange\n", s);
+      if (!(1 <= t && t <= G->nv))
+         xerror("glp_write_maxflow: t = %d: sink node number out of ran"
+            "ge\n", t);
+      if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+         xerror("glp_write_mincost: a_cap = %d; invalid offset\n",
+            a_cap);
+      xprintf("Writing maximum flow problem data to `%s'...\n",
+         fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++;
+      xfprintf(fp, "n %d s\n", s), count++;
+      xfprintf(fp, "n %d t\n", t), count++;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  if (a_cap >= 0)
+               memcpy(&cap, (char *)a->data + a_cap, sizeof(double));
+            else
+               cap = 1.0;
+            xfprintf(fp, "a %d %d %.*g\n",
+               a->tail->i, a->head->i, DBL_DIG, cap), count++;
+         }
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_asnprob - read assignment problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_asnprob(glp_graph *G, int v_set, int a_cost,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_asnprob reads assignment problem data in DIMACS
+*  format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_vertex *v;
+      glp_arc *a;
+      int nv, na, n1, i, j, k, ret = 0;
+      double cost;
+      char *flag = NULL;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_read_asnprob: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_read_asnprob: a_cost = %d; invalid offset\n",
+            a_cost);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading assignment problem data from `%s'...\n", fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "asn") != 0)
+         error(csa, "wrong problem designator; `asn' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+         error(csa, "number of nodes missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &na) == 0 && na >= 0))
+         error(csa, "number of arcs missing or invalid");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      flag = xcalloc(1+nv, sizeof(char));
+      memset(&flag[1], 0, nv * sizeof(char));
+      n1 = 0;
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "node number %d out of range", i);
+         if (flag[i])
+            error(csa, "duplicate descriptor of node %d", i);
+         flag[i] = 1, n1++;
+         end_of_line(csa);
+      }
+      xprintf(
+         "Assignment problem has %d + %d = %d node%s and %d arc%s\n",
+         n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s");
+      if (v_set >= 0)
+      {  for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            k = (flag[i] ? 0 : 1);
+            memcpy((char *)v->data + v_set, &k, sizeof(int));
+         }
+      }
+      /* read arc descriptor lines */
+      for (k = 1; k <= na; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "a") != 0)
+            error(csa, "wrong line designator; `a' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "starting node number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "starting node number %d out of range", i);
+         if (!flag[i])
+            error(csa, "node %d cannot be a starting node", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "ending node number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "ending node number %d out of range", j);
+         if (flag[j])
+            error(csa, "node %d cannot be an ending node", j);
+         read_field(csa);
+         if (str2num(csa->field, &cost) != 0)
+            error(csa, "arc cost missing or invalid");
+         check_int(csa, cost);
+         a = glp_add_arc(G, i, j);
+         if (a_cost >= 0)
+            memcpy((char *)a->data + a_cost, &cost, sizeof(double));
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_asnprob - write assignment problem data in DIMACS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_asnprob(glp_graph *G, int v_set, int a_cost,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_asnprob writes assignment problem data in
+*  DIMACS format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *a;
+      int i, k, count = 0, ret;
+      double cost;
+      if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int))
+         xerror("glp_write_asnprob: v_set = %d; invalid offset\n",
+            v_set);
+      if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+         xerror("glp_write_asnprob: a_cost = %d; invalid offset\n",
+            a_cost);
+      xprintf("Writing assignment problem data to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++;
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         if (v_set >= 0)
+            memcpy(&k, (char *)v->data + v_set, sizeof(int));
+         else
+            k = (v->out != NULL ? 0 : 1);
+         if (k == 0)
+            xfprintf(fp, "n %d\n", i), count++;
+      }
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (a = v->out; a != NULL; a = a->t_next)
+         {  if (a_cost >= 0)
+               memcpy(&cost, (char *)a->data + a_cost, sizeof(double));
+            else
+               cost = 1.0;
+            xfprintf(fp, "a %d %d %.*g\n",
+               a->tail->i, a->head->i, DBL_DIG, cost), count++;
+         }
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_ccdata - read graph in DIMACS clique/coloring format
+*
+*  SYNOPSIS
+*
+*  int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_ccdata reads an (undirected) graph in DIMACS
+*  clique/coloring format from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      glp_vertex *v;
+      int i, j, k, nv, ne, ret = 0;
+      double w;
+      char *flag = NULL;
+      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+         xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n",
+            v_wgt);
+      glp_erase_graph(G, G->v_size, G->a_size);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading graph from `%s'...\n", fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "edge") != 0)
+         error(csa, "wrong problem designator; `edge' expected");
+      read_field(csa);
+      if (!(str2int(csa->field, &nv) == 0 && nv >= 0))
+         error(csa, "number of vertices missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &ne) == 0 && ne >= 0))
+         error(csa, "number of edges missing or invalid");
+      xprintf("Graph has %d vert%s and %d edge%s\n",
+         nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s");
+      if (nv > 0) glp_add_vertices(G, nv);
+      end_of_line(csa);
+      /* read node descriptor lines */
+      flag = xcalloc(1+nv, sizeof(char));
+      memset(&flag[1], 0, nv * sizeof(char));
+      if (v_wgt >= 0)
+      {  w = 1.0;
+         for (i = 1; i <= nv; i++)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
+         }
+      }
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "n") != 0) break;
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "vertex number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "vertex number %d out of range", i);
+         if (flag[i])
+            error(csa, "duplicate descriptor of vertex %d", i);
+         read_field(csa);
+         if (str2num(csa->field, &w) != 0)
+            error(csa, "vertex weight missing or invalid");
+         check_int(csa, w);
+         if (v_wgt >= 0)
+         {  v = G->v[i];
+            memcpy((char *)v->data + v_wgt, &w, sizeof(double));
+         }
+         flag[i] = 1;
+         end_of_line(csa);
+      }
+      xfree(flag), flag = NULL;
+      /* read edge descriptor lines */
+      for (k = 1; k <= ne; k++)
+      {  if (k > 1) read_designator(csa);
+         if (strcmp(csa->field, "e") != 0)
+            error(csa, "wrong line designator; `e' expected");
+         read_field(csa);
+         if (str2int(csa->field, &i) != 0)
+            error(csa, "first vertex number missing or invalid");
+         if (!(1 <= i && i <= nv))
+            error(csa, "first vertex number %d out of range", i);
+         read_field(csa);
+         if (str2int(csa->field, &j) != 0)
+            error(csa, "second vertex number missing or invalid");
+         if (!(1 <= j && j <= nv))
+            error(csa, "second vertex number %d out of range", j);
+         glp_add_arc(G, i, j);
+         end_of_line(csa);
+      }
+      xprintf("%d lines were read\n", csa->count);
+done: if (ret) glp_erase_graph(G, G->v_size, G->a_size);
+      if (csa->fp != NULL) xfclose(csa->fp);
+      if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_ccdata - write graph in DIMACS clique/coloring format
+*
+*  SYNOPSIS
+*
+*  int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_ccdata writes the specified graph in DIMACS
+*  clique/coloring format to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname)
+{     XFILE *fp;
+      glp_vertex *v;
+      glp_arc *e;
+      int i, count = 0, ret;
+      double w;
+      if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double))
+         xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n",
+            v_wgt);
+      xprintf("Writing graph to `%s'\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         G->name == NULL ? "unknown" : G->name), count++;
+      xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++;
+      if (v_wgt >= 0)
+      {  for (i = 1; i <= G->nv; i++)
+         {  v = G->v[i];
+            memcpy(&w, (char *)v->data + v_wgt, sizeof(double));
+            if (w != 1.0)
+               xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++;
+         }
+      }
+      for (i = 1; i <= G->nv; i++)
+      {  v = G->v[i];
+         for (e = v->out; e != NULL; e = e->t_next)
+            xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++;
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_prob - read problem data in GLPK format
+*
+*  SYNOPSIS
+*
+*  int glp_read_prob(glp_prob *P, int flags, const char *fname);
+*
+*  The routine glp_read_prob reads problem data in GLPK LP/MIP format
+*  from a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_read_prob(glp_prob *P, int flags, const char *fname)
+{     struct csa _csa, *csa = &_csa;
+      int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL,
+         *ia = NULL, *ja = NULL;
+      double lb, ub, temp, *ar = NULL;
+      char *rf = NULL, *cf = NULL;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_read_prob: P = %p; invalid problem object\n",
+            P);
+      if (flags != 0)
+         xerror("glp_read_prob: flags = %d; invalid parameter\n",
+            flags);
+      if (fname == NULL)
+         xerror("glp_read_prob: fname = %d; invalid parameter\n",
+            fname);
+      glp_erase_prob(P);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading problem data from `%s'...\n", fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "lp") == 0)
+         mip = 0;
+      else if (strcmp(csa->field, "mip") == 0)
+         mip = 1;
+      else
+         error(csa, "wrong problem designator; `lp' or `mip' expected\n"
+            );
+      read_field(csa);
+      if (strcmp(csa->field, "min") == 0)
+         glp_set_obj_dir(P, GLP_MIN);
+      else if (strcmp(csa->field, "max") == 0)
+         glp_set_obj_dir(P, GLP_MAX);
+      else
+         error(csa, "objective sense missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &m) == 0 && m >= 0))
+         error(csa, "number of rows missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &n) == 0 && n >= 0))
+         error(csa, "number of columns missing or invalid");
+      read_field(csa);
+      if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0))
+         error(csa, "number of constraint coefficients missing or inval"
+            "id");
+      if (m > 0)
+      {  glp_add_rows(P, m);
+         for (i = 1; i <= m; i++)
+            glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0);
+      }
+      if (n > 0)
+      {  glp_add_cols(P, n);
+         for (j = 1; j <= n; j++)
+         {  if (!mip)
+               glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0);
+            else
+               glp_set_col_kind(P, j, GLP_BV);
+         }
+      }
+      end_of_line(csa);
+      /* allocate working arrays */
+      rf = xcalloc(1+m, sizeof(char));
+      memset(rf, 0, 1+m);
+      cf = xcalloc(1+n, sizeof(char));
+      memset(cf, 0, 1+n);
+      ln = xcalloc(1+nnz, sizeof(int));
+      ia = xcalloc(1+nnz, sizeof(int));
+      ja = xcalloc(1+nnz, sizeof(int));
+      ar = xcalloc(1+nnz, sizeof(double));
+      /* read descriptor lines */
+      ne = 0;
+      for (;;)
+      {  read_designator(csa);
+         if (strcmp(csa->field, "i") == 0)
+         {  /* row descriptor */
+            read_field(csa);
+            if (str2int(csa->field, &i) != 0)
+               error(csa, "row number missing or invalid");
+            if (!(1 <= i && i <= m))
+               error(csa, "row number out of range");
+            read_field(csa);
+            if (strcmp(csa->field, "f") == 0)
+               type = GLP_FR;
+            else if (strcmp(csa->field, "l") == 0)
+               type = GLP_LO;
+            else if (strcmp(csa->field, "u") == 0)
+               type = GLP_UP;
+            else if (strcmp(csa->field, "d") == 0)
+               type = GLP_DB;
+            else if (strcmp(csa->field, "s") == 0)
+               type = GLP_FX;
+            else
+               error(csa, "row type missing or invalid");
+            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+            {  read_field(csa);
+               if (str2num(csa->field, &lb) != 0)
+                  error(csa, "row lower bound/fixed value missing or in"
+                     "valid");
+            }
+            else
+               lb = 0.0;
+            if (type == GLP_UP || type == GLP_DB)
+            {  read_field(csa);
+               if (str2num(csa->field, &ub) != 0)
+                  error(csa, "row upper bound missing or invalid");
+            }
+            else
+               ub = 0.0;
+            if (rf[i] & 0x01)
+               error(csa, "duplicate row descriptor");
+            glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01;
+         }
+         else if (strcmp(csa->field, "j") == 0)
+         {  /* column descriptor */
+            read_field(csa);
+            if (str2int(csa->field, &j) != 0)
+               error(csa, "column number missing or invalid");
+            if (!(1 <= j && j <= n))
+               error(csa, "column number out of range");
+            if (!mip)
+               kind = GLP_CV;
+            else
+            {  read_field(csa);
+               if (strcmp(csa->field, "c") == 0)
+                  kind = GLP_CV;
+               else if (strcmp(csa->field, "i") == 0)
+                  kind = GLP_IV;
+               else if (strcmp(csa->field, "b") == 0)
+               {  kind = GLP_IV;
+                  type = GLP_DB, lb = 0.0, ub = 1.0;
+                  goto skip;
+               }
+               else
+                  error(csa, "column kind missing or invalid");
+            }
+            read_field(csa);
+            if (strcmp(csa->field, "f") == 0)
+               type = GLP_FR;
+            else if (strcmp(csa->field, "l") == 0)
+               type = GLP_LO;
+            else if (strcmp(csa->field, "u") == 0)
+               type = GLP_UP;
+            else if (strcmp(csa->field, "d") == 0)
+               type = GLP_DB;
+            else if (strcmp(csa->field, "s") == 0)
+               type = GLP_FX;
+            else
+               error(csa, "column type missing or invalid");
+            if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+            {  read_field(csa);
+               if (str2num(csa->field, &lb) != 0)
+                  error(csa, "column lower bound/fixed value missing or"
+                     " invalid");
+            }
+            else
+               lb = 0.0;
+            if (type == GLP_UP || type == GLP_DB)
+            {  read_field(csa);
+               if (str2num(csa->field, &ub) != 0)
+                  error(csa, "column upper bound missing or invalid");
+            }
+            else
+               ub = 0.0;
+skip:       if (cf[j] & 0x01)
+               error(csa, "duplicate column descriptor");
+            glp_set_col_kind(P, j, kind);
+            glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01;
+         }
+         else if (strcmp(csa->field, "a") == 0)
+         {  /* coefficient descriptor */
+            read_field(csa);
+            if (str2int(csa->field, &i) != 0)
+               error(csa, "row number missing or invalid");
+            if (!(0 <= i && i <= m))
+               error(csa, "row number out of range");
+            read_field(csa);
+            if (str2int(csa->field, &j) != 0)
+               error(csa, "column number missing or invalid");
+            if (!((i == 0 ? 0 : 1) <= j && j <= n))
+               error(csa, "column number out of range");
+            read_field(csa);
+            if (i == 0)
+            {  if (str2num(csa->field, &temp) != 0)
+                  error(csa, "objective %s missing or invalid",
+                     j == 0 ? "constant term" : "coefficient");
+               if (cf[j] & 0x10)
+                  error(csa, "duplicate objective %s",
+                     j == 0 ? "constant term" : "coefficient");
+               glp_set_obj_coef(P, j, temp), cf[j] |= 0x10;
+            }
+            else
+            {  if (str2num(csa->field, &temp) != 0)
+                  error(csa, "constraint coefficient missing or invalid"
+                     );
+               if (ne == nnz)
+                  error(csa, "too many constraint coefficient descripto"
+                     "rs");
+               ln[++ne] = csa->count;
+               ia[ne] = i, ja[ne] = j, ar[ne] = temp;
+            }
+         }
+         else if (strcmp(csa->field, "n") == 0)
+         {  /* symbolic name descriptor */
+            read_field(csa);
+            if (strcmp(csa->field, "p") == 0)
+            {  /* problem name */
+               read_field(csa);
+               if (P->name != NULL)
+                  error(csa, "duplicate problem name");
+               glp_set_prob_name(P, csa->field);
+            }
+            else if (strcmp(csa->field, "z") == 0)
+            {  /* objective name */
+               read_field(csa);
+               if (P->obj != NULL)
+                  error(csa, "duplicate objective name");
+               glp_set_obj_name(P, csa->field);
+            }
+            else if (strcmp(csa->field, "i") == 0)
+            {  /* row name */
+               read_field(csa);
+               if (str2int(csa->field, &i) != 0)
+                  error(csa, "row number missing or invalid");
+               if (!(1 <= i && i <= m))
+                  error(csa, "row number out of range");
+               read_field(csa);
+               if (P->row[i]->name != NULL)
+                  error(csa, "duplicate row name");
+               glp_set_row_name(P, i, csa->field);
+            }
+            else if (strcmp(csa->field, "j") == 0)
+            {  /* column name */
+               read_field(csa);
+               if (str2int(csa->field, &j) != 0)
+                  error(csa, "column number missing or invalid");
+               if (!(1 <= j && j <= n))
+                  error(csa, "column number out of range");
+               read_field(csa);
+               if (P->col[j]->name != NULL)
+                  error(csa, "duplicate column name");
+               glp_set_col_name(P, j, csa->field);
+            }
+            else
+               error(csa, "object designator missing or invalid");
+         }
+         else if (strcmp(csa->field, "e") == 0)
+            break;
+         else
+            error(csa, "line designator missing or invalid");
+         end_of_line(csa);
+      }
+      if (ne < nnz)
+         error(csa, "too few constraint coefficient descriptors");
+      xassert(ne == nnz);
+      k = glp_check_dup(m, n, ne, ia, ja);
+      xassert(0 <= k && k <= nnz);
+      if (k > 0)
+      {  csa->count = ln[k];
+         error(csa, "duplicate constraint coefficient");
+      }
+      glp_load_matrix(P, ne, ia, ja, ar);
+      /* print some statistics */
+      if (P->name != NULL)
+         xprintf("Problem: %s\n", P->name);
+      if (P->obj != NULL)
+         xprintf("Objective: %s\n", P->obj);
+      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+         m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ?
+         "" : "s");
+      if (glp_get_num_int(P) > 0)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         if (ni == 1)
+         {  if (nb == 0)
+               xprintf("One variable is integer\n");
+            else
+               xprintf("One variable is binary\n");
+         }
+         else
+         {  xprintf("%d integer variables, ", ni);
+            if (nb == 0)
+               xprintf("none");
+            else if (nb == 1)
+               xprintf("one");
+            else if (nb == ni)
+               xprintf("all");
+            else
+               xprintf("%d", nb);
+            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+         }
+      }
+      xprintf("%d lines were read\n", csa->count);
+      /* problem data has been successfully read */
+      glp_sort_matrix(P);
+      ret = 0;
+done: if (csa->fp != NULL) xfclose(csa->fp);
+      if (rf != NULL) xfree(rf);
+      if (cf != NULL) xfree(cf);
+      if (ln != NULL) xfree(ln);
+      if (ia != NULL) xfree(ia);
+      if (ja != NULL) xfree(ja);
+      if (ar != NULL) xfree(ar);
+      if (ret) glp_erase_prob(P);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_prob - write problem data in GLPK format
+*
+*  SYNOPSIS
+*
+*  int glp_write_prob(glp_prob *P, int flags, const char *fname);
+*
+*  The routine glp_write_prob writes problem data in GLPK LP/MIP format
+*  to a text file.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine returns zero. Otherwise
+*  it prints an error message and returns non-zero. */
+
+int glp_write_prob(glp_prob *P, int flags, const char *fname)
+{     XFILE *fp;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int mip, i, j, count, ret;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_write_prob: P = %p; invalid problem object\n",
+            P);
+      if (flags != 0)
+         xerror("glp_write_prob: flags = %d; invalid parameter\n",
+            flags);
+      if (fname == NULL)
+         xerror("glp_write_prob: fname = %d; invalid parameter\n",
+            fname);
+      xprintf("Writing problem data to `%s'...\n", fname);
+      fp = xfopen(fname, "w"), count = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* write problem line */
+      mip = (glp_get_num_int(P) > 0);
+      xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip",
+         P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???",
+         P->m, P->n, P->nnz), count++;
+      if (P->name != NULL)
+         xfprintf(fp, "n p %s\n", P->name), count++;
+      if (P->obj != NULL)
+         xfprintf(fp, "n z %s\n", P->obj), count++;
+      /* write row descriptors */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         if (row->type == GLP_FX && row->lb == 0.0)
+            goto skip1;
+         xfprintf(fp, "i %d ", i), count++;
+         if (row->type == GLP_FR)
+            xfprintf(fp, "f\n");
+         else if (row->type == GLP_LO)
+            xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb);
+         else if (row->type == GLP_UP)
+            xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub);
+         else if (row->type == GLP_DB)
+            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG,
+                  row->ub);
+         else if (row->type == GLP_FX)
+            xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb);
+         else
+            xassert(row != row);
+skip1:   if (row->name != NULL)
+            xfprintf(fp, "n i %d %s\n", i, row->name), count++;
+      }
+      /* write column descriptors */
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (!mip && col->type == GLP_LO && col->lb == 0.0)
+            goto skip2;
+         if (mip && col->kind == GLP_IV && col->type == GLP_DB &&
+             col->lb == 0.0 && col->ub == 1.0)
+            goto skip2;
+         xfprintf(fp, "j %d ", j), count++;
+         if (mip)
+         {  if (col->kind == GLP_CV)
+               xfprintf(fp, "c ");
+            else if (col->kind == GLP_IV)
+               xfprintf(fp, "i ");
+            else
+               xassert(col != col);
+         }
+         if (col->type == GLP_FR)
+            xfprintf(fp, "f\n");
+         else if (col->type == GLP_LO)
+            xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb);
+         else if (col->type == GLP_UP)
+            xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub);
+         else if (col->type == GLP_DB)
+            xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG,
+                  col->ub);
+         else if (col->type == GLP_FX)
+            xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb);
+         else
+            xassert(col != col);
+skip2:   if (col->name != NULL)
+            xfprintf(fp, "n j %d %s\n", j, col->name), count++;
+      }
+      /* write objective coefficient descriptors */
+      if (P->c0 != 0.0)
+         xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++;
+      for (j = 1; j <= P->n; j++)
+      {  col = P->col[j];
+         if (col->coef != 0.0)
+            xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef),
+               count++;
+      }
+      /* write constraint coefficient descriptors */
+      for (i = 1; i <= P->m; i++)
+      {  row = P->row[i];
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG,
+               aij->val), count++;
+      }
+      /* write end line */
+      xfprintf(fp, "e o f\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/**********************************************************************/
+
+int glp_read_cnfsat(glp_prob *P, const char *fname)
+{     /* read CNF-SAT problem data in DIMACS format */
+      struct csa _csa, *csa = &_csa;
+      int m, n, i, j, len, neg, rhs, ret = 0, *ind = NULL;
+      double *val = NULL;
+      char *map = NULL;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_read_cnfsat: P = %p; invalid problem object\n",
+            P);
+      if (fname == NULL)
+         xerror("glp_read_cnfsat: fname = %p; invalid parameter\n",
+            fname);
+      glp_erase_prob(P);
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->fname = fname;
+      csa->fp = NULL;
+      csa->count = 0;
+      csa->c = '\n';
+      csa->field[0] = '\0';
+      csa->empty = csa->nonint = 0;
+      xprintf("Reading CNF-SAT problem data from `%s'...\n", fname);
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         longjmp(csa->jump, 1);
+      }
+      /* read problem line */
+      read_designator(csa);
+      if (strcmp(csa->field, "p") != 0)
+         error(csa, "problem line missing or invalid");
+      read_field(csa);
+      if (strcmp(csa->field, "cnf") != 0)
+         error(csa, "wrong problem designator; `cnf' expected\n");
+      read_field(csa);
+      if (!(str2int(csa->field, &n) == 0 && n >= 0))
+         error(csa, "number of variables missing or invalid\n");
+      read_field(csa);
+      if (!(str2int(csa->field, &m) == 0 && m >= 0))
+         error(csa, "number of clauses missing or invalid\n");
+      xprintf("Instance has %d variable%s and %d clause%s\n",
+         n, n == 1 ? "" : "s", m, m == 1 ? "" : "s");
+      end_of_line(csa);
+      if (m > 0)
+         glp_add_rows(P, m);
+      if (n > 0)
+      {  glp_add_cols(P, n);
+         for (j = 1; j <= n; j++)
+            glp_set_col_kind(P, j, GLP_BV);
+      }
+      /* allocate working arrays */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      map = xcalloc(1+n, sizeof(char));
+      for (j = 1; j <= n; j++) map[j] = 0;
+      /* read clauses */
+      for (i = 1; i <= m; i++)
+      {  /* read i-th clause */
+         len = 0, rhs = 1;
+         for (;;)
+         {  /* skip white-space characters */
+            while (csa->c == ' ' || csa->c == '\n')
+               read_char(csa);
+            /* read term */
+            read_field(csa);
+            if (str2int(csa->field, &j) != 0)
+               error(csa, "variable number missing or invalid\n");
+            if (j > 0)
+               neg = 0;
+            else if (j < 0)
+               neg = 1, j = -j, rhs--;
+            else
+               break;
+            if (!(1 <= j && j <= n))
+               error(csa, "variable number out of range\n");
+            if (map[j])
+               error(csa, "duplicate variable number\n");
+            len++, ind[len] = j, val[len] = (neg ? -1.0 : +1.0);
+            map[j] = 1;
+         }
+         glp_set_row_bnds(P, i, GLP_LO, (double)rhs, 0.0);
+         glp_set_mat_row(P, i, len, ind, val);
+         while (len > 0) map[ind[len--]] = 0;
+      }
+      xprintf("%d lines were read\n", csa->count);
+      /* problem data has been successfully read */
+      glp_sort_matrix(P);
+done: if (csa->fp != NULL) xfclose(csa->fp);
+      if (ind != NULL) xfree(ind);
+      if (val != NULL) xfree(val);
+      if (map != NULL) xfree(map);
+      if (ret) glp_erase_prob(P);
+      return ret;
+}
+
+/**********************************************************************/
+
+int glp_check_cnfsat(glp_prob *P)
+{     /* check for CNF-SAT problem instance */
+      int m = P->m;
+      int n = P->n;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, neg;
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_check_cnfsat: P = %p; invalid problem object\n",
+            P);
+      /* check columns */
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         /* the variable should be binary */
+         if (!(col->kind == GLP_IV && col->type == GLP_DB &&
+               col->lb == 0.0 && col->ub == 1.0))
+            return 1;
+      }
+      /* objective function should be zero */
+      if (P->c0 != 0.0)
+         return 2;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         if (col->coef != 0.0)
+            return 3;
+      }
+      /* check rows */
+      for (i = 1; i <= m; i++)
+      {  row = P->row[i];
+         /* the row should be of ">=" type */
+         if (row->type != GLP_LO)
+            return 4;
+         /* check constraint coefficients */
+         neg = 0;
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  /* the constraint coefficient should be +1 or -1 */
+            if (aij->val == +1.0)
+               ;
+            else if (aij->val == -1.0)
+               neg++;
+            else
+               return 5;
+         }
+         /* the right-hand side should be (1 - neg), where neg is the
+            number of negative constraint coefficients in the row */
+         if (row->lb != (double)(1 - neg))
+            return 6;
+      }
+      /* congratulations; this is CNF-SAT */
+      return 0;
+}
+
+/**********************************************************************/
+
+int glp_write_cnfsat(glp_prob *P, const char *fname)
+{     /* write CNF-SAT problem data in DIMACS format */
+      XFILE *fp = NULL;
+      GLPAIJ *aij;
+      int i, j, len, count = 0, ret;
+      char s[50];
+      if (P == NULL || P->magic != GLP_PROB_MAGIC)
+         xerror("glp_write_cnfsat: P = %p; invalid problem object\n",
+            P);
+      if (glp_check_cnfsat(P) != 0)
+      {  xprintf("glp_write_cnfsat: problem object does not encode CNF-"
+            "SAT instance\n");
+         ret = 1;
+         goto done;
+      }
+      xprintf("Writing CNF-SAT problem data to `%s'...\n", fname);
+      fp = xfopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xfprintf(fp, "c %s\n",
+         P->name == NULL ? "unknown" : P->name), count++;
+      xfprintf(fp, "p cnf %d %d\n", P->n, P->m), count++;
+      for (i = 1; i <= P->m; i++)
+      {  len = 0;
+         for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  j = aij->col->j;
+            if (aij->val < 0.0) j = -j;
+            sprintf(s, "%d", j);
+            if (len > 0 && len + 1 + strlen(s) > 72)
+               xfprintf(fp, "\n"), count++, len = 0;
+            xfprintf(fp, "%s%s", len == 0 ? "" : " ", s);
+            if (len > 0) len++;
+            len += strlen(s);
+         }
+         if (len > 0 && len + 1 + 1 > 72)
+            xfprintf(fp, "\n"), count++, len = 0;
+         xfprintf(fp, "%s0\n", len == 0 ? "" : " "), count++;
+      }
+      xfprintf(fp, "c eof\n"), count++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      xprintf("%d lines were written\n", count);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpenv.h
===================================================================
--- deps/glpk/src/glpenv.h	(revision 9)
+++ deps/glpk/src/glpenv.h	(revision 9)
@@ -0,0 +1,228 @@
+/* glpenv.h (GLPK environment) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPENV_H
+#define GLPENV_H
+
+#include "glpstd.h"
+#include "glplib.h"
+
+typedef struct ENV ENV;
+typedef struct MEM MEM;
+typedef struct XFILE XFILE;
+
+#define ENV_MAGIC 0x454E5631
+/* environment block magic value */
+
+#define TERM_BUF_SIZE 4096
+/* terminal output buffer size, in bytes */
+
+#define IOERR_MSG_SIZE 1024
+/* i/o error message buffer size, in bytes */
+
+#define MEM_MAGIC 0x4D454D31
+/* memory block descriptor magic value */
+
+struct ENV
+{     /* environment block */
+      int magic;
+      /* magic value used for debugging */
+      char version[7+1];
+      /* version string returned by the routine glp_version */
+      /*--------------------------------------------------------------*/
+      /* terminal output */
+      char *term_buf; /* char term_buf[TERM_BUF_SIZE]; */
+      /* terminal output buffer */
+      int term_out;
+      /* flag to enable/disable terminal output */
+      int (*term_hook)(void *info, const char *s);
+      /* user-defined routine to intercept terminal output */
+      void *term_info;
+      /* transit pointer (cookie) passed to the routine term_hook */
+      FILE *tee_file;
+      /* output stream used to copy terminal output */
+      /*--------------------------------------------------------------*/
+      /* error handling */
+      const char *err_file;
+      /* value of the __FILE__ macro passed to glp_error */
+      int err_line;
+      /* value of the __LINE__ macro passed to glp_error */
+      void (*err_hook)(void *info);
+      /* user-defined routine to intercept abnormal termination */
+      void *err_info;
+      /* transit pointer (cookie) passed to the routine err_hook */
+      /*--------------------------------------------------------------*/
+      /* memory allocation */
+      glp_long mem_limit;
+      /* maximal amount of memory (in bytes) available for dynamic
+         allocation */
+      MEM *mem_ptr;
+      /* pointer to the linked list of allocated memory blocks */
+      int mem_count;
+      /* total number of currently allocated memory blocks */
+      int mem_cpeak;
+      /* peak value of mem_count */
+      glp_long mem_total;
+      /* total amount of currently allocated memory (in bytes; is the
+         sum of the size field over all memory block descriptors) */
+      glp_long mem_tpeak;
+      /* peak value of mem_total */
+      /*--------------------------------------------------------------*/
+      /* stream input/output */
+      XFILE *file_ptr;
+      /* pointer to the linked list of active stream descriptors */
+      char *ioerr_msg; /* char ioerr_msg[IOERR_MSG_SIZE]; */
+      /* input/output error message buffer */
+      /*--------------------------------------------------------------*/
+      /* shared libraries support */
+      void *h_odbc;
+      /* handle to ODBC shared library */
+      void *h_mysql;
+      /* handle to MySQL shared library */
+};
+
+struct MEM
+{     /* memory block descriptor */
+      int flag;
+      /* descriptor flag */
+      int size;
+      /* size of block (in bytes, including descriptor) */
+      MEM *prev;
+      /* pointer to previous memory block descriptor */
+      MEM *next;
+      /* pointer to next memory block descriptor */
+};
+
+struct XFILE
+{     /* input/output stream descriptor */
+      int type;
+      /* stream handle type: */
+#define FH_FILE   0x11  /* FILE   */
+#define FH_ZLIB   0x22  /* gzFile */
+      void *fh;
+      /* pointer to stream handle */
+      XFILE *prev;
+      /* pointer to previous stream descriptor */
+      XFILE *next;
+      /* pointer to next stream descriptor */
+};
+
+#define XEOF (-1)
+
+#define get_env_ptr _glp_get_env_ptr
+ENV *get_env_ptr(void);
+/* retrieve pointer to environment block */
+
+#define tls_set_ptr _glp_tls_set_ptr
+void tls_set_ptr(void *ptr);
+/* store global pointer in TLS */
+
+#define tls_get_ptr _glp_tls_get_ptr
+void *tls_get_ptr(void);
+/* retrieve global pointer from TLS */
+
+#define xprintf glp_printf
+void glp_printf(const char *fmt, ...);
+/* write formatted output to the terminal */
+
+#define xvprintf glp_vprintf
+void glp_vprintf(const char *fmt, va_list arg);
+/* write formatted output to the terminal */
+
+#ifndef GLP_ERROR_DEFINED
+#define GLP_ERROR_DEFINED
+typedef void (*_glp_error)(const char *fmt, ...);
+#endif
+
+#define xerror glp_error_(__FILE__, __LINE__)
+_glp_error glp_error_(const char *file, int line);
+/* display error message and terminate execution */
+
+#define xassert(expr) \
+      ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
+void glp_assert_(const char *expr, const char *file, int line);
+/* check for logical condition */
+
+#define xmalloc glp_malloc
+void *glp_malloc(int size);
+/* allocate memory block */
+
+#define xcalloc glp_calloc
+void *glp_calloc(int n, int size);
+/* allocate memory block */
+
+#define xfree glp_free
+void glp_free(void *ptr);
+/* free memory block */
+
+#define xtime glp_time
+glp_long glp_time(void);
+/* determine current universal time */
+
+#define xdifftime glp_difftime
+double glp_difftime(glp_long t1, glp_long t0);
+/* compute difference between two time values, in seconds */
+
+#define lib_err_msg _glp_lib_err_msg
+void lib_err_msg(const char *msg);
+
+#define xerrmsg _glp_lib_xerrmsg
+const char *xerrmsg(void);
+
+#define xfopen _glp_lib_xfopen
+XFILE *xfopen(const char *fname, const char *mode);
+
+#define xferror _glp_lib_xferror
+int xferror(XFILE *file);
+
+#define xfeof _glp_lib_xfeof
+int xfeof(XFILE *file);
+
+#define xfgetc _glp_lib_xfgetc
+int xfgetc(XFILE *file);
+
+#define xfputc _glp_lib_xfputc
+int xfputc(int c, XFILE *file);
+
+#define xfflush _glp_lib_xfflush
+int xfflush(XFILE *fp);
+
+#define xfclose _glp_lib_xfclose
+int xfclose(XFILE *file);
+
+#define xfprintf _glp_lib_xfprintf
+int xfprintf(XFILE *file, const char *fmt, ...);
+
+#define xdlopen _glp_xdlopen
+void *xdlopen(const char *module);
+
+#define xdlsym _glp_xdlsym
+void *xdlsym(void *h, const char *symbol);
+
+#define xdlclose _glp_xdlclose
+void xdlclose(void *h);
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpenv01.c
===================================================================
--- deps/glpk/src/glpenv01.c	(revision 9)
+++ deps/glpk/src/glpenv01.c	(revision 9)
@@ -0,0 +1,233 @@
+/* glpenv01.c (environment initialization/termination) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_env - initialize GLPK environment
+*
+*  SYNOPSIS
+*
+*  int glp_init_env(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_env initializes the GLPK environment. Normally
+*  the application program does not need to call this routine, because
+*  it is called automatically on the first call to any API routine.
+*
+*  RETURNS
+*
+*  The routine glp_init_env returns one of the following codes:
+*
+*  0 - initialization successful;
+*  1 - environment has been already initialized;
+*  2 - initialization failed (insufficient memory);
+*  3 - initialization failed (unsupported programming model). */
+
+int glp_init_env(void)
+{     ENV *env;
+      int ok;
+      /* check if the programming model is supported */
+      ok = (CHAR_BIT == 8 && sizeof(char) == 1 &&
+         sizeof(short) == 2 && sizeof(int) == 4 &&
+         (sizeof(void *) == 4 || sizeof(void *) == 8));
+      if (!ok) return 3;
+      /* check if the environment is already initialized */
+      if (tls_get_ptr() != NULL) return 1;
+      /* allocate and initialize the environment block */
+      env = malloc(sizeof(ENV));
+      if (env == NULL) return 2;
+      env->magic = ENV_MAGIC;
+      sprintf(env->version, "%d.%d",
+         GLP_MAJOR_VERSION, GLP_MINOR_VERSION);
+      env->term_buf = malloc(TERM_BUF_SIZE);
+      if (env->term_buf == NULL)
+      {  free(env);
+         return 2;
+      }
+      env->term_out = GLP_ON;
+      env->term_hook = NULL;
+      env->term_info = NULL;
+      env->tee_file = NULL;
+      env->err_file = "";
+      env->err_line = 0;
+      env->err_hook = NULL;
+      env->err_info = NULL;
+      env->mem_limit.hi = 0x7FFFFFFF, env->mem_limit.lo = 0xFFFFFFFF;
+      env->mem_ptr = NULL;
+      env->mem_count = env->mem_cpeak = 0;
+      env->mem_total = env->mem_tpeak = xlset(0);
+      env->file_ptr = NULL;
+      env->ioerr_msg = malloc(IOERR_MSG_SIZE);
+      if (env->ioerr_msg == NULL)
+      {  free(env->term_buf);
+         free(env);
+         return 2;
+      }
+      strcpy(env->ioerr_msg, "No error");
+      env->h_odbc = env->h_mysql = NULL;
+      /* save pointer to the environment block */
+      tls_set_ptr(env);
+      /* initialization successful */
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  get_env_ptr - retrieve pointer to environment block
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  ENV *get_env_ptr(void);
+*
+*  DESCRIPTION
+*
+*  The routine get_env_ptr retrieves and returns a pointer to the GLPK
+*  environment block.
+*
+*  If the GLPK environment has not been initialized yet, the routine
+*  performs initialization. If initialization fails, the routine prints
+*  an error message to stderr and terminates the program.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the environment block. */
+
+ENV *get_env_ptr(void)
+{     ENV *env = tls_get_ptr();
+      /* check if the environment has been initialized */
+      if (env == NULL)
+      {  /* not initialized yet; perform initialization */
+         if (glp_init_env() != 0)
+         {  /* initialization failed; display an error message */
+            fprintf(stderr, "GLPK initialization failed\n");
+            fflush(stderr);
+            /* and abnormally terminate the program */
+            abort();
+         }
+         /* initialization successful; retrieve the pointer */
+         env = tls_get_ptr();
+      }
+      /* check if the environment block is valid */
+      if (env->magic != ENV_MAGIC)
+      {  fprintf(stderr, "Invalid GLPK environment\n");
+         fflush(stderr);
+         abort();
+      }
+      return env;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_version - determine library version
+*
+*  SYNOPSIS
+*
+*  const char *glp_version(void);
+*
+*  RETURNS
+*
+*  The routine glp_version returns a pointer to a null-terminated
+*  character string, which specifies the version of the GLPK library in
+*  the form "X.Y", where X is the major version number, and Y is the
+*  minor version number, for example, "4.16". */
+
+const char *glp_version(void)
+{     ENV *env = get_env_ptr();
+      return env->version;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_free_env - free GLPK environment
+*
+*  SYNOPSIS
+*
+*  int glp_free_env(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_free_env frees all resources used by GLPK routines
+*  (memory blocks, etc.) which are currently still in use.
+*
+*  Normally the application program does not need to call this routine,
+*  because GLPK routines always free all unused resources. However, if
+*  the application program even has deleted all problem objects, there
+*  will be several memory blocks still allocated for the library needs.
+*  For some reasons the application program may want GLPK to free this
+*  memory, in which case it should call glp_free_env.
+*
+*  Note that a call to glp_free_env invalidates all problem objects as
+*  if no GLPK routine were called.
+*
+*  RETURNS
+*
+*  0 - termination successful;
+*  1 - environment is inactive (was not initialized). */
+
+int glp_free_env(void)
+{     ENV *env = tls_get_ptr();
+      MEM *desc;
+      /* check if the environment is active */
+      if (env == NULL) return 1;
+      /* check if the environment block is valid */
+      if (env->magic != ENV_MAGIC)
+      {  fprintf(stderr, "Invalid GLPK environment\n");
+         fflush(stderr);
+         abort();
+      }
+      /* close handles to shared libraries */
+      if (env->h_odbc != NULL)
+         xdlclose(env->h_odbc);
+      if (env->h_mysql != NULL)
+         xdlclose(env->h_mysql);
+      /* close streams which are still open */
+      while (env->file_ptr != NULL)
+         xfclose(env->file_ptr);
+      /* free memory blocks which are still allocated */
+      while (env->mem_ptr != NULL)
+      {  desc = env->mem_ptr;
+         env->mem_ptr = desc->next;
+         free(desc);
+      }
+      /* invalidate the environment block */
+      env->magic = -1;
+      /* free memory allocated to the environment block */
+      free(env->term_buf);
+      free(env->ioerr_msg);
+      free(env);
+      /* reset a pointer to the environment block */
+      tls_set_ptr(NULL);
+      /* termination successful */
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/src/glpenv02.c
===================================================================
--- deps/glpk/src/glpenv02.c	(revision 9)
+++ deps/glpk/src/glpenv02.c	(revision 9)
@@ -0,0 +1,73 @@
+/* glpenv02.c (thread local storage) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+
+static void *tls = NULL;
+/* in a re-entrant version of the package this variable must be placed
+   in the Thread Local Storage (TLS) */
+
+/***********************************************************************
+*  NAME
+*
+*  tls_set_ptr - store global pointer in TLS
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  void tls_set_ptr(void *ptr);
+*
+*  DESCRIPTION
+*
+*  The routine tls_set_ptr stores a pointer specified by the parameter
+*  ptr in the Thread Local Storage (TLS). */
+
+void tls_set_ptr(void *ptr)
+{     tls = ptr;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  tls_get_ptr - retrieve global pointer from TLS
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  void *tls_get_ptr(void);
+*
+*  RETURNS
+*
+*  The routine tls_get_ptr returns a pointer previously stored by the
+*  routine tls_set_ptr. If the latter has not been called yet, NULL is
+*  returned. */
+
+void *tls_get_ptr(void)
+{     void *ptr;
+      ptr = tls;
+      return ptr;
+}
+
+/* eof */
Index: deps/glpk/src/glpenv03.c
===================================================================
--- deps/glpk/src/glpenv03.c	(revision 9)
+++ deps/glpk/src/glpenv03.c	(revision 9)
@@ -0,0 +1,228 @@
+/* glpenv03.c (terminal output) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_printf - write formatted output to terminal
+*
+*  SYNOPSIS
+*
+*  void glp_printf(const char *fmt, ...);
+*
+*  DESCRIPTION
+*
+*  The routine glp_printf uses the format control string fmt to format
+*  its parameters and writes the formatted output to the terminal. */
+
+void glp_printf(const char *fmt, ...)
+{     va_list arg;
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_vprintf - write formatted output to terminal
+*
+*  SYNOPSIS
+*
+*  void glp_vprintf(const char *fmt, va_list arg);
+*
+*  DESCRIPTION
+*
+*  The routine glp_vprintf uses the format control string fmt to format
+*  its parameters specified by the list arg and writes the formatted
+*  output to the terminal. */
+
+void glp_vprintf(const char *fmt, va_list arg)
+{     ENV *env = get_env_ptr();
+      /* if terminal output is disabled, do nothing */
+      if (!env->term_out) goto skip;
+      /* format the output */
+      vsprintf(env->term_buf, fmt, arg);
+      /* pass the output to the user-defined routine */
+      if (env->term_hook != NULL)
+      {  if (env->term_hook(env->term_info, env->term_buf) != 0)
+            goto skip;
+      }
+      /* send the output to the terminal */
+      fputs(env->term_buf, stdout);
+      fflush(stdout);
+      /* copy the output to the text file */
+      if (env->tee_file != NULL)
+      {  fputs(env->term_buf, env->tee_file);
+         fflush(env->tee_file);
+      }
+skip: return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_term_out - enable/disable terminal output
+*
+*  SYNOPSIS
+*
+*  int glp_term_out(int flag);
+*
+*  DESCRIPTION
+*
+*  Depending on the parameter flag the routine glp_term_out enables or
+*  disables terminal output performed by glpk routines:
+*
+*  GLP_ON  - enable terminal output;
+*  GLP_OFF - disable terminal output.
+*
+*  RETURNS
+*
+*  The routine glp_term_out returns the previous value of the terminal
+*  output flag. */
+
+int glp_term_out(int flag)
+{     ENV *env = get_env_ptr();
+      int old = env->term_out;
+      if (!(flag == GLP_ON || flag == GLP_OFF))
+         xerror("glp_term_out: flag = %d; invalid value\n", flag);
+      env->term_out = flag;
+      return old;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_term_hook - install hook to intercept terminal output
+*
+*  SYNOPSIS
+*
+*  void glp_term_hook(int (*func)(void *info, const char *s),
+*     void *info);
+*
+*  DESCRIPTION
+*
+*  The routine glp_term_hook installs a user-defined hook routine to
+*  intercept all terminal output performed by glpk routines.
+*
+*  This feature can be used to redirect the terminal output to other
+*  destination, for example to a file or a text window.
+*
+*  The parameter func specifies the user-defined hook routine. It is
+*  called from an internal printing routine, which passes to it two
+*  parameters: info and s. The parameter info is a transit pointer,
+*  specified in the corresponding call to the routine glp_term_hook;
+*  it may be used to pass some information to the hook routine. The
+*  parameter s is a pointer to the null terminated character string,
+*  which is intended to be written to the terminal. If the hook routine
+*  returns zero, the printing routine writes the string s to the
+*  terminal in a usual way; otherwise, if the hook routine returns
+*  non-zero, no terminal output is performed.
+*
+*  To uninstall the hook routine the parameters func and info should be
+*  specified as NULL. */
+
+void glp_term_hook(int (*func)(void *info, const char *s), void *info)
+{     ENV *env = get_env_ptr();
+      if (func == NULL)
+      {  env->term_hook = NULL;
+         env->term_info = NULL;
+      }
+      else
+      {  env->term_hook = func;
+         env->term_info = info;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_open_tee - start copying terminal output to text file
+*
+*  SYNOPSIS
+*
+*  int glp_open_tee(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_open_tee starts copying all the terminal output to
+*  an output text file, whose name is specified by the character string
+*  fname.
+*
+*  RETURNS
+*
+*  0 - operation successful
+*  1 - copying terminal output is already active
+*  2 - unable to create output file */
+
+int glp_open_tee(const char *fname)
+{     ENV *env = get_env_ptr();
+      if (env->tee_file != NULL)
+      {  /* copying terminal output is already active */
+         return 1;
+      }
+      env->tee_file = fopen(fname, "w");
+      if (env->tee_file == NULL)
+      {  /* unable to create output file */
+         return 2;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_close_tee - stop copying terminal output to text file
+*
+*  SYNOPSIS
+*
+*  int glp_close_tee(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_close_tee stops copying the terminal output to the
+*  output text file previously open by the routine glp_open_tee closing
+*  that file.
+*
+*  RETURNS
+*
+*  0 - operation successful
+*  1 - copying terminal output was not started */
+
+int glp_close_tee(void)
+{     ENV *env = get_env_ptr();
+      if (env->tee_file == NULL)
+      {  /* copying terminal output was not started */
+         return 1;
+      }
+      fclose(env->tee_file);
+      env->tee_file = NULL;
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/src/glpenv04.c
===================================================================
--- deps/glpk/src/glpenv04.c	(revision 9)
+++ deps/glpk/src/glpenv04.c	(revision 9)
@@ -0,0 +1,124 @@
+/* glpenv04.c (error handling) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_error - display error message and terminate execution
+*
+*  SYNOPSIS
+*
+*  void glp_error(const char *fmt, ...);
+*
+*  DESCRIPTION
+*
+*  The routine glp_error (implemented as a macro) formats its
+*  parameters using the format control string fmt, writes the formatted
+*  message to the terminal, and abnormally terminates the program. */
+
+static void error(const char *fmt, ...)
+{     ENV *env = get_env_ptr();
+      va_list arg;
+      env->term_out = GLP_ON;
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      xprintf("Error detected in file %s at line %d\n", env->err_file,
+         env->err_line);
+      if (env->err_hook != NULL)
+         env->err_hook(env->err_info);
+      abort();
+      exit(EXIT_FAILURE);
+      /* no return */
+}
+
+_glp_error glp_error_(const char *file, int line)
+{     ENV *env = get_env_ptr();
+      env->err_file = file;
+      env->err_line = line;
+      return error;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_assert - check for logical condition
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  void glp_assert(int expr);
+*
+*  DESCRIPTION
+*
+*  The routine glp_assert (implemented as a macro) checks for a logical
+*  condition specified by the parameter expr. If the condition is false
+*  (i.e. the value of expr is zero), the routine writes a message to
+*  the terminal and abnormally terminates the program. */
+
+void glp_assert_(const char *expr, const char *file, int line)
+{     glp_error_(file, line)("Assertion failed: %s\n", expr);
+      /* no return */
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_error_hook - install hook to intercept abnormal termination
+*
+*  SYNOPSIS
+*
+*  void glp_error_hook(void (*func)(void *info), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine glp_error_hook installs a user-defined hook routine to
+*  intercept abnormal termination.
+*
+*  The parameter func specifies the user-defined hook routine. It is
+*  called from the routine glp_error before the latter calls the abort
+*  function to abnormally terminate the application program because of
+*  fatal error. The parameter info is a transit pointer, specified in
+*  the corresponding call to the routine glp_error_hook; it may be used
+*  to pass some information to the hook routine.
+*
+*  To uninstall the hook routine the parameters func and info should be
+*  specified as NULL. */
+
+void glp_error_hook(void (*func)(void *info), void *info)
+{     ENV *env = get_env_ptr();
+      if (func == NULL)
+      {  env->err_hook = NULL;
+         env->err_info = NULL;
+      }
+      else
+      {  env->err_hook = func;
+         env->err_info = info;
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpenv05.c
===================================================================
--- deps/glpk/src/glpenv05.c	(revision 9)
+++ deps/glpk/src/glpenv05.c	(revision 9)
@@ -0,0 +1,225 @@
+/* glpenv05.c (memory allocation) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/* some processors need data to be properly aligned; the macro
+   align_datasize enlarges the specified size of a data item to provide
+   a proper alignment of immediately following data */
+
+#define align_datasize(size) ((((size) + 15) / 16) * 16)
+/* 16 bytes is sufficient in both 32- and 64-bit environments
+   (8 bytes is not sufficient in 64-bit environment due to jmp_buf) */
+
+/***********************************************************************
+*  NAME
+*
+*  glp_malloc - allocate memory block
+*
+*  SYNOPSIS
+*
+*  void *glp_malloc(int size);
+*
+*  DESCRIPTION
+*
+*  The routine glp_malloc allocates a memory block of size bytes long.
+*
+*  Note that being allocated the memory block contains arbitrary data
+*  (not binary zeros).
+*
+*  RETURNS
+*
+*  The routine glp_malloc returns a pointer to the allocated block.
+*  To free this block the routine glp_free (not free!) must be used. */
+
+void *glp_malloc(int size)
+{     ENV *env = get_env_ptr();
+      MEM *desc;
+      int size_of_desc = align_datasize(sizeof(MEM));
+      if (size < 1 || size > INT_MAX - size_of_desc)
+         xerror("glp_malloc: size = %d; invalid parameter\n", size);
+      size += size_of_desc;
+      if (xlcmp(xlset(size),
+          xlsub(env->mem_limit, env->mem_total)) > 0)
+         xerror("glp_malloc: memory limit exceeded\n");
+      if (env->mem_count == INT_MAX)
+         xerror("glp_malloc: too many memory blocks allocated\n");
+      desc = malloc(size);
+      if (desc == NULL)
+         xerror("glp_malloc: no memory available\n");
+      memset(desc, '?', size);
+      desc->flag = MEM_MAGIC;
+      desc->size = size;
+      desc->prev = NULL;
+      desc->next = env->mem_ptr;
+      if (desc->next != NULL) desc->next->prev = desc;
+      env->mem_ptr = desc;
+      env->mem_count++;
+      if (env->mem_cpeak < env->mem_count)
+         env->mem_cpeak = env->mem_count;
+      env->mem_total = xladd(env->mem_total, xlset(size));
+      if (xlcmp(env->mem_tpeak, env->mem_total) < 0)
+         env->mem_tpeak = env->mem_total;
+      return (void *)((char *)desc + size_of_desc);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_calloc - allocate memory block
+*
+*  SYNOPSIS
+*
+*  void *glp_calloc(int n, int size);
+*
+*  DESCRIPTION
+*
+*  The routine glp_calloc allocates a memory block of (n*size) bytes
+*  long.
+*
+*  Note that being allocated the memory block contains arbitrary data
+*  (not binary zeros).
+*
+*  RETURNS
+*
+*  The routine glp_calloc returns a pointer to the allocated block.
+*  To free this block the routine glp_free (not free!) must be used. */
+
+void *glp_calloc(int n, int size)
+{     if (n < 1)
+         xerror("glp_calloc: n = %d; invalid parameter\n", n);
+      if (size < 1)
+         xerror("glp_calloc: size = %d; invalid parameter\n", size);
+      if (n > INT_MAX / size)
+         xerror("glp_calloc: n = %d; size = %d; array too big\n", n,
+            size);
+      return xmalloc(n * size);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_free - free memory block
+*
+*  SYNOPSIS
+*
+*  void glp_free(void *ptr);
+*
+*  DESCRIPTION
+*
+*  The routine glp_free frees a memory block pointed to by ptr, which
+*  was previuosly allocated by the routine glp_malloc or glp_calloc. */
+
+void glp_free(void *ptr)
+{     ENV *env = get_env_ptr();
+      MEM *desc;
+      int size_of_desc = align_datasize(sizeof(MEM));
+      if (ptr == NULL)
+         xerror("glp_free: ptr = %p; null pointer\n", ptr);
+      desc = (void *)((char *)ptr - size_of_desc);
+      if (desc->flag != MEM_MAGIC)
+         xerror("glp_free: ptr = %p; invalid pointer\n", ptr);
+      if (env->mem_count == 0 ||
+          xlcmp(env->mem_total, xlset(desc->size)) < 0)
+         xerror("glp_free: memory allocation error\n");
+      if (desc->prev == NULL)
+         env->mem_ptr = desc->next;
+      else
+         desc->prev->next = desc->next;
+      if (desc->next == NULL)
+         ;
+      else
+         desc->next->prev = desc->prev;
+      env->mem_count--;
+      env->mem_total = xlsub(env->mem_total, xlset(desc->size));
+      memset(desc, '?', size_of_desc);
+      free(desc);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mem_limit - set memory usage limit
+*
+*  SYNOPSIS
+*
+*  void glp_mem_limit(int limit);
+*
+*  DESCRIPTION
+*
+*  The routine glp_mem_limit limits the amount of memory available for
+*  dynamic allocation (in GLPK routines) to limit megabytes. */
+
+void glp_mem_limit(int limit)
+{     ENV *env = get_env_ptr();
+      if (limit < 0)
+         xerror("glp_mem_limit: limit = %d; invalid parameter\n",
+            limit);
+      env->mem_limit = xlmul(xlset(limit), xlset(1 << 20));
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_mem_usage - get memory usage information
+*
+*  SYNOPSIS
+*
+*  void glp_mem_usage(int *count, int *cpeak, glp_long *total,
+*     glp_long *tpeak);
+*
+*  DESCRIPTION
+*
+*  The routine glp_mem_usage reports some information about utilization
+*  of the memory by GLPK routines. Information is stored to locations
+*  specified by corresponding parameters (see below). Any parameter can
+*  be specified as NULL, in which case corresponding information is not
+*  stored.
+*
+*  *count is the number of the memory blocks currently allocated by the
+*  routines xmalloc and xcalloc (one call to xmalloc or xcalloc results
+*  in allocating one memory block).
+*
+*  *cpeak is the peak value of *count reached since the initialization
+*  of the GLPK library environment.
+*
+*  *total is the total amount, in bytes, of the memory blocks currently
+*  allocated by the routines xmalloc and xcalloc.
+*
+*  *tpeak is the peak value of *total reached since the initialization
+*  of the GLPK library envirionment. */
+
+void glp_mem_usage(int *count, int *cpeak, glp_long *total,
+      glp_long *tpeak)
+{     ENV *env = get_env_ptr();
+      if (count != NULL) *count = env->mem_count;
+      if (cpeak != NULL) *cpeak = env->mem_cpeak;
+      if (total != NULL) *total = env->mem_total;
+      if (tpeak != NULL) *tpeak = env->mem_tpeak;
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpenv06.c
===================================================================
--- deps/glpk/src/glpenv06.c	(revision 9)
+++ deps/glpk/src/glpenv06.c	(revision 9)
@@ -0,0 +1,172 @@
+/* glpenv06.c (standard time) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_time - determine current universal time
+*
+*  SYNOPSIS
+*
+*  glp_long glp_time(void);
+*
+*  RETURNS
+*
+*  The routine glp_time returns the current universal time (UTC), in
+*  milliseconds, elapsed since 00:00:00 GMT January 1, 1970. */
+
+static const int epoch = 2440588; /* = jday(1, 1, 1970) */
+
+/* POSIX version ******************************************************/
+
+#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY)
+
+#include <sys/time.h>
+#include <time.h>
+
+glp_long glp_time(void)
+{     struct timeval tv;
+      struct tm *tm;
+      glp_long t;
+      int j;
+      gettimeofday(&tv, NULL);
+      tm = gmtime(&tv.tv_sec);
+      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+      xassert(j >= 0);
+      t = xlset(j - epoch);
+      t = xlmul(t, xlset(24));
+      t = xladd(t, xlset(tm->tm_hour));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_min));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_sec));
+      t = xlmul(t, xlset(1000));
+      t = xladd(t, xlset(tv.tv_usec / 1000));
+      return t;
+}
+
+/* Windows version ****************************************************/
+
+#elif defined(__WOE__)
+
+#include <windows.h>
+
+glp_long glp_time(void)
+{     SYSTEMTIME st;
+      glp_long t;
+      int j;
+      GetSystemTime(&st);
+      j = jday(st.wDay, st.wMonth, st.wYear);
+      xassert(j >= 0);
+      t = xlset(j - epoch);
+      t = xlmul(t, xlset(24));
+      t = xladd(t, xlset(st.wHour));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(st.wMinute));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(st.wSecond));
+      t = xlmul(t, xlset(1000));
+      t = xladd(t, xlset(st.wMilliseconds));
+      return t;
+}
+
+/* portable ISO C version *********************************************/
+
+#else
+
+#include <time.h>
+
+glp_long glp_time(void)
+{     time_t timer;
+      struct tm *tm;
+      glp_long t;
+      int j;
+      timer = time(NULL);
+      tm = gmtime(&timer);
+      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+      xassert(j >= 0);
+      t = xlset(j - epoch);
+      t = xlmul(t, xlset(24));
+      t = xladd(t, xlset(tm->tm_hour));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_min));
+      t = xlmul(t, xlset(60));
+      t = xladd(t, xlset(tm->tm_sec));
+      t = xlmul(t, xlset(1000));
+      return t;
+}
+
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  glp_difftime - compute difference between two time values
+*
+*  SYNOPSIS
+*
+*  double glp_difftime(glp_long t1, glp_long t0);
+*
+*  RETURNS
+*
+*  The routine glp_difftime returns the difference between two time
+*  values t1 and t0, expressed in seconds. */
+
+double glp_difftime(glp_long t1, glp_long t0)
+{     return
+         xltod(xlsub(t1, t0)) / 1000.0;
+}
+
+/**********************************************************************/
+
+#if 0
+int main(void)
+{     glp_long t;
+      glp_ldiv d;
+      int ttt, ss, mm, hh, day, month, year;
+      char s[50];
+      t = glp_time();
+      xprintf("t = %s\n", xltoa(t, s));
+      d = xldiv(t, xlset(1000));
+      ttt = d.rem.lo, t = d.quot;
+      d = xldiv(t, xlset(60));
+      ss = d.rem.lo, t = d.quot;
+      d = xldiv(t, xlset(60));
+      mm = d.rem.lo, t = d.quot;
+      d = xldiv(t, xlset(24));
+      hh = d.rem.lo, t = d.quot;
+      xassert(jdate(t.lo + epoch, &day, &month, &year) == 0);
+      xprintf("%04d-%02d-%02d %02d:%02d:%02d.%03d\n", year, month, day,
+         hh, mm, ss, ttt);
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpenv07.c
===================================================================
--- deps/glpk/src/glpenv07.c	(revision 9)
+++ deps/glpk/src/glpenv07.c	(revision 9)
@@ -0,0 +1,672 @@
+/* glpenv07.c (stream input/output) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpenv.h"
+
+/***********************************************************************
+*  NAME
+*
+*  lib_err_msg - save error message string
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  void lib_err_msg(const char *msg);
+*
+*  DESCRIPTION
+*
+*  The routine lib_err_msg saves an error message string specified by
+*  the parameter msg. The message is obtained by some library routines
+*  with a call to strerror(errno). */
+
+void lib_err_msg(const char *msg)
+{     ENV *env = get_env_ptr();
+      int len = strlen(msg);
+      if (len >= IOERR_MSG_SIZE)
+         len = IOERR_MSG_SIZE - 1;
+      memcpy(env->ioerr_msg, msg, len);
+      if (len > 0 && env->ioerr_msg[len-1] == '\n') len--;
+      env->ioerr_msg[len] = '\0';
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xerrmsg - retrieve error message string
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  const char *xerrmsg(void);
+*
+*  RETURNS
+*
+*  The routine xerrmsg returns a pointer to an error message string
+*  previously set by some library routine to indicate an error. */
+
+const char *xerrmsg(void)
+{     ENV *env = get_env_ptr();
+      return env->ioerr_msg;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfopen - open a stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  XFILE *xfopen(const char *fname, const char *mode);
+*
+*  DESCRIPTION
+*
+*  The routine xfopen opens the file whose name is a string pointed to
+*  by fname and associates a stream with it.
+*
+*  The parameter mode points to a string, which indicates the open mode
+*  and should be one of the following:
+*
+*  "r"   open text file for reading;
+*  "w"   truncate to zero length or create text file for writing;
+*  "rb"  open binary file for reading;
+*  "wb"  truncate to zero length or create binary file for writing.
+*
+*  RETURNS
+*
+*  The routine xfopen returns a pointer to the object controlling the
+*  stream. If the open operation fails, xfopen returns NULL. */
+
+static void *c_fopen(const char *fname, const char *mode);
+static void *z_fopen(const char *fname, const char *mode);
+
+static int is_gz_file(const char *fname)
+{     char *ext = strrchr(fname, '.');
+      return ext != NULL && strcmp(ext, ".gz") == 0;
+}
+
+XFILE *xfopen(const char *fname, const char *mode)
+{     ENV *env = get_env_ptr();
+      XFILE *fp;
+      int type;
+      void *fh;
+      if (!is_gz_file(fname))
+      {  type = FH_FILE;
+         fh = c_fopen(fname, mode);
+      }
+      else
+      {  type = FH_ZLIB;
+         fh = z_fopen(fname, mode);
+      }
+      if (fh == NULL)
+      {  fp = NULL;
+         goto done;
+      }
+      fp = xmalloc(sizeof(XFILE));
+      fp->type = type;
+      fp->fh = fh;
+      fp->prev = NULL;
+      fp->next = env->file_ptr;
+      if (fp->next != NULL) fp->next->prev = fp;
+      env->file_ptr = fp;
+done: return fp;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfgetc - read character from the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfgetc(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  If the end-of-file indicator for the input stream pointed to by fp
+*  is not set and a next character is present, the routine xfgetc
+*  obtains that character as an unsigned char converted to an int and
+*  advances the associated file position indicator for the stream (if
+*  defined).
+*
+*  RETURNS
+*
+*  If the end-of-file indicator for the stream is set, or if the
+*  stream is at end-of-file, the end-of-file indicator for the stream
+*  is set and the routine xfgetc returns XEOF. Otherwise, the routine
+*  xfgetc returns the next character from the input stream pointed to
+*  by fp. If a read error occurs, the error indicator for the stream is
+*  set and the xfgetc routine returns XEOF.
+*
+*  Note: An end-of-file and a read error can be distinguished by use of
+*  the routines xfeof and xferror. */
+
+static int c_fgetc(void *fh);
+static int z_fgetc(void *fh);
+
+int xfgetc(XFILE *fp)
+{     int c;
+      switch (fp->type)
+      {  case FH_FILE:
+            c = c_fgetc(fp->fh);
+            break;
+         case FH_ZLIB:
+            c = z_fgetc(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return c;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfputc - write character to the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfputc(int c, XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xfputc writes the character specified by c (converted
+*  to an unsigned char) to the output stream pointed to by fp, at the
+*  position indicated by the associated file position indicator (if
+*  defined), and advances the indicator appropriately.
+*
+*  RETURNS
+*
+*  The routine xfputc returns the character written. If a write error
+*  occurs, the error indicator for the stream is set and xfputc returns
+*  XEOF. */
+
+static int c_fputc(int c, void *fh);
+static int z_fputc(int c, void *fh);
+
+int xfputc(int c, XFILE *fp)
+{     switch (fp->type)
+      {  case FH_FILE:
+            c = c_fputc(c, fp->fh);
+            break;
+         case FH_ZLIB:
+            c = z_fputc(c, fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return c;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xferror - test error indicator for the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xferror(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xferror tests the error indicator for the stream
+*  pointed to by fp.
+*
+*  RETURNS
+*
+*  The routine xferror returns non-zero if and only if the error
+*  indicator is set for the stream. */
+
+static int c_ferror(void *fh);
+static int z_ferror(void *fh);
+
+int xferror(XFILE *fp)
+{     int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_ferror(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_ferror(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfeof - test end-of-file indicator for the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfeof(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xfeof tests the end-of-file indicator for the stream
+*  pointed to by fp.
+*
+*  RETURNS
+*
+*  The routine xfeof returns non-zero if and only if the end-of-file
+*  indicator is set for the stream. */
+
+static int c_feof(void *fh);
+static int z_feof(void *fh);
+
+int xfeof(XFILE *fp)
+{     int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_feof(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_feof(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return ret;
+}
+
+int xfprintf(XFILE *file, const char *fmt, ...)
+{     ENV *env = get_env_ptr();
+      int cnt, j;
+      va_list arg;
+      va_start(arg, fmt);
+      cnt = vsprintf(env->term_buf, fmt, arg);
+      va_end(arg);
+      for (j = 0; j < cnt; j++)
+      {  if (xfputc(env->term_buf[j], file) < 0)
+         {  cnt = -1;
+            break;
+         }
+      }
+      return cnt;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfflush - flush the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfflush(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  The routine xfflush causes any unwritten data for the output stream
+*  pointed to by fp to be written to the associated file.
+*
+*  RETURNS
+*
+*  The routine xfflush returns zero if the stream was successfully
+*  flushed. Otherwise, xfflush sets the error indicator for the stream
+*  and returns XEOF. */
+
+static int c_fflush(void *fh);
+static int z_fflush(void *fh);
+
+int xfflush(XFILE *fp)
+{     int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_fflush(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_fflush(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xfclose - close the stream
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  int xfclose(XFILE *fp);
+*
+*  DESCRIPTION
+*
+*  A successful call to the routine xfclose causes the stream pointed
+*  to by fp to be flushed and the associated file to be closed. Whether
+*  or not the call succeeds, the stream is disassociated from the file.
+*
+*  RETURNS
+*
+*  The routine xfclose returns zero if the stream was successfully
+*  closed, or XEOF if any errors were detected. */
+
+static int c_fclose(void *fh);
+static int z_fclose(void *fh);
+
+int xfclose(XFILE *fp)
+{     ENV *env = get_env_ptr();
+      int ret;
+      switch (fp->type)
+      {  case FH_FILE:
+            ret = c_fclose(fp->fh);
+            break;
+         case FH_ZLIB:
+            ret = z_fclose(fp->fh);
+            break;
+         default:
+            xassert(fp != fp);
+      }
+      fp->type = 0xF00BAD;
+      if (fp->prev == NULL)
+         env->file_ptr = fp->next;
+      else
+         fp->prev->next = fp->next;
+      if (fp->next == NULL)
+         ;
+      else
+         fp->next->prev = fp->prev;
+      xfree(fp);
+      return ret;
+}
+
+/***********************************************************************
+*  The following routines implement stream input/output based on the
+*  standard C streams. */
+
+static void *c_fopen(const char *fname, const char *mode)
+{     FILE *fh;
+      if (strcmp(fname, "/dev/stdin") == 0)
+         fh = stdin;
+      else if (strcmp(fname, "/dev/stdout") == 0)
+         fh = stdout;
+      else if (strcmp(fname, "/dev/stderr") == 0)
+         fh = stderr;
+      else
+         fh = fopen(fname, mode);
+      if (fh == NULL)
+         lib_err_msg(strerror(errno));
+      return fh;
+}
+
+static int c_fgetc(void *_fh)
+{     FILE *fh = _fh;
+      int c;
+      if (ferror(fh) || feof(fh))
+      {  c = XEOF;
+         goto done;
+      }
+      c = fgetc(fh);
+      if (ferror(fh))
+      {  lib_err_msg(strerror(errno));
+         c = XEOF;
+      }
+      else if (feof(fh))
+         c = XEOF;
+      else
+         xassert(0x00 <= c && c <= 0xFF);
+done: return c;
+}
+
+static int c_fputc(int c, void *_fh)
+{     FILE *fh = _fh;
+      if (ferror(fh))
+      {  c = XEOF;
+         goto done;
+      }
+      c = (unsigned char)c;
+      fputc(c, fh);
+      if (ferror(fh))
+      {  lib_err_msg(strerror(errno));
+         c = XEOF;
+      }
+done: return c;
+}
+
+static int c_ferror(void *_fh)
+{     FILE *fh = _fh;
+      return ferror(fh);
+}
+
+static int c_feof(void *_fh)
+{     FILE *fh = _fh;
+      return feof(fh);
+}
+
+static int c_fflush(void *_fh)
+{     FILE *fh = _fh;
+      int ret;
+      ret = fflush(fh);
+      if (ret != 0)
+      {  lib_err_msg(strerror(errno));
+         ret = XEOF;
+      }
+      return ret;
+}
+
+static int c_fclose(void *_fh)
+{     FILE *fh = _fh;
+      int ret;
+      if (fh == stdin)
+         ret = 0;
+      else if (fh == stdout || fh == stderr)
+         fflush(fh), ret = 0;
+      else
+         ret = fclose(fh);
+      if (ret != 0)
+      {  lib_err_msg(strerror(errno));
+         ret = XEOF;
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  The following routines implement stream input/output based on the
+*  zlib library, which provides processing .gz files "on the fly". */
+
+/*#ifndef HAVE_ZLIB*/
+#if 0 /* 27/IV-2011 */
+
+static void *z_fopen(const char *fname, const char *mode)
+{     xassert(fname == fname);
+      xassert(mode == mode);
+      lib_err_msg("Compressed files not supported");
+      return NULL;
+}
+
+static int z_fgetc(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_fputc(int c, void *fh)
+{     xassert(c != c);
+      xassert(fh != fh);
+      return 0;
+}
+
+static int z_ferror(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_feof(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_fflush(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+static int z_fclose(void *fh)
+{     xassert(fh != fh);
+      return 0;
+}
+
+#else
+
+#include "zlib/zlib.h"
+
+struct z_file
+{     /* .gz file handle */
+      gzFile file;
+      /* pointer to .gz stream */
+      int err;
+      /* i/o error indicator */
+      int eof;
+      /* end-of-file indicator */
+};
+
+static void *z_fopen(const char *fname, const char *mode)
+{     struct z_file *fh;
+      gzFile file;
+      if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0)
+         mode = "rb";
+      else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0)
+         mode = "wb";
+      else
+      {  lib_err_msg("Invalid open mode");
+         fh = NULL;
+         goto done;
+      }
+      file = gzopen(fname, mode);
+      if (file == NULL)
+      {  lib_err_msg(strerror(errno));
+         fh = NULL;
+         goto done;
+      }
+      fh = xmalloc(sizeof(struct z_file));
+      fh->file = file;
+      fh->err = fh->eof = 0;
+done: return fh;
+}
+
+static int z_fgetc(void *_fh)
+{     struct z_file *fh = _fh;
+      int c;
+      if (fh->err || fh->eof)
+      {  c = XEOF;
+         goto done;
+      }
+      c = gzgetc(fh->file);
+      if (c < 0)
+      {  int errnum;
+         const char *msg;
+         msg = gzerror(fh->file, &errnum);
+         if (errnum == Z_STREAM_END)
+            fh->eof = 1;
+         else if (errnum == Z_ERRNO)
+         {  fh->err = 1;
+            lib_err_msg(strerror(errno));
+         }
+         else
+         {  fh->err = 1;
+            lib_err_msg(msg);
+         }
+         c = XEOF;
+      }
+      else
+         xassert(0x00 <= c && c <= 0xFF);
+done: return c;
+}
+
+static int z_fputc(int c, void *_fh)
+{     struct z_file *fh = _fh;
+      if (fh->err)
+      {  c = XEOF;
+         goto done;
+      }
+      c = (unsigned char)c;
+      if (gzputc(fh->file, c) < 0)
+      {  int errnum;
+         const char *msg;
+         fh->err = 1;
+         msg = gzerror(fh->file, &errnum);
+         if (errnum == Z_ERRNO)
+            lib_err_msg(strerror(errno));
+         else
+            lib_err_msg(msg);
+         c = XEOF;
+      }
+done: return c;
+}
+
+static int z_ferror(void *_fh)
+{     struct z_file *fh = _fh;
+      return fh->err;
+}
+
+static int z_feof(void *_fh)
+{     struct z_file *fh = _fh;
+      return fh->eof;
+}
+
+static int z_fflush(void *_fh)
+{     struct z_file *fh = _fh;
+      int ret;
+      ret = gzflush(fh->file, Z_FINISH);
+      if (ret == Z_OK)
+         ret = 0;
+      else
+      {  int errnum;
+         const char *msg;
+         fh->err = 1;
+         msg = gzerror(fh->file, &errnum);
+         if (errnum == Z_ERRNO)
+            lib_err_msg(strerror(errno));
+         else
+            lib_err_msg(msg);
+         ret = XEOF;
+      }
+      return ret;
+}
+
+static int z_fclose(void *_fh)
+{     struct z_file *fh = _fh;
+      gzclose(fh->file);
+      xfree(fh);
+      return 0;
+}
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpenv08.c
===================================================================
--- deps/glpk/src/glpenv08.c	(revision 9)
+++ deps/glpk/src/glpenv08.c	(revision 9)
@@ -0,0 +1,156 @@
+/* glpenv08.c (shared library support) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpenv.h"
+
+/* GNU version ********************************************************/
+
+#if defined(HAVE_LTDL)
+
+#include <ltdl.h>
+
+void *xdlopen(const char *module)
+{     void *h = NULL;
+      if (lt_dlinit() != 0)
+      {  lib_err_msg(lt_dlerror());
+         goto done;
+      }
+      h = lt_dlopen(module);
+      if (h == NULL)
+      {  lib_err_msg(lt_dlerror());
+         if (lt_dlexit() != 0)
+            xerror("xdlopen: %s\n", lt_dlerror());
+      }
+done: return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     void *ptr;
+      xassert(h != NULL);
+      ptr = lt_dlsym(h, symbol);
+      if (ptr == NULL)
+         xerror("xdlsym: %s: %s\n", symbol, lt_dlerror());
+      return ptr;
+}
+
+void xdlclose(void *h)
+{     xassert(h != NULL);
+      if (lt_dlclose(h) != 0)
+         xerror("xdlclose: %s\n", lt_dlerror());
+      if (lt_dlexit() != 0)
+         xerror("xdlclose: %s\n", lt_dlerror());
+      return;
+}
+
+/* POSIX version ******************************************************/
+
+#elif defined(HAVE_DLFCN)
+
+#include <dlfcn.h>
+
+void *xdlopen(const char *module)
+{     void *h;
+      h = dlopen(module, RTLD_NOW);
+      if (h == NULL)
+         lib_err_msg(dlerror());
+      return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     void *ptr;
+      xassert(h != NULL);
+      ptr = dlsym(h, symbol);
+      if (ptr == NULL)
+         xerror("xdlsym: %s: %s\n", symbol, dlerror());
+      return ptr;
+}
+
+void xdlclose(void *h)
+{     xassert(h != NULL);
+      if (dlclose(h) != 0)
+         xerror("xdlclose: %s\n", dlerror());
+      return;
+}
+
+/* Windows version ****************************************************/
+
+#elif defined(__WOE__)
+
+#include <windows.h>
+
+void *xdlopen(const char *module)
+{     void *h;
+      h = LoadLibrary(module);
+      if (h == NULL)
+      {  char msg[20];
+         sprintf(msg, "Error %d", GetLastError());
+         lib_err_msg(msg);
+      }
+      return h;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     void *ptr;
+      xassert(h != NULL);
+      ptr = GetProcAddress(h, symbol);
+      if (ptr == NULL)
+         xerror("xdlsym: %s: Error %d\n", symbol, GetLastError());
+      return ptr;
+}
+
+void xdlclose(void *h)
+{     xassert(h != NULL);
+      if (!FreeLibrary(h))
+         xerror("xdlclose: Error %d\n", GetLastError());
+      return;
+}
+
+/* NULL version *******************************************************/
+
+#else
+
+void *xdlopen(const char *module)
+{     xassert(module == module);
+      lib_err_msg("Shared libraries not supported");
+      return NULL;
+}
+
+void *xdlsym(void *h, const char *symbol)
+{     xassert(h != h);
+      xassert(symbol != symbol);
+      return NULL;
+}
+
+void xdlclose(void *h)
+{     xassert(h != h);
+      return;
+}
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpfhv.c
===================================================================
--- deps/glpk/src/glpfhv.c	(revision 9)
+++ deps/glpk/src/glpfhv.c	(revision 9)
@@ -0,0 +1,774 @@
+/* glpfhv.c (LP basis factorization, FHV eta file version) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpfhv.h"
+#include "glpenv.h"
+#define xfault xerror
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the basis matrix */
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_create_it - create LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  FHV *fhv_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_create_it creates a program object, which represents
+*  a factorization of LP basis.
+*
+*  RETURNS
+*
+*  The routine fhv_create_it returns a pointer to the object created. */
+
+FHV *fhv_create_it(void)
+{     FHV *fhv;
+      fhv = xmalloc(sizeof(FHV));
+      fhv->m_max = fhv->m = 0;
+      fhv->valid = 0;
+      fhv->luf = luf_create_it();
+      fhv->hh_max = 50;
+      fhv->hh_nfs = 0;
+      fhv->hh_ind = fhv->hh_ptr = fhv->hh_len = NULL;
+      fhv->p0_row = fhv->p0_col = NULL;
+      fhv->cc_ind = NULL;
+      fhv->cc_val = NULL;
+      fhv->upd_tol = 1e-6;
+      fhv->nnz_h = 0;
+      return fhv;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_factorize - compute LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
+*     int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_factorize computes the factorization of the basis
+*  matrix B specified by the routine col.
+*
+*  The parameter fhv specified the basis factorization data structure
+*  created by the routine fhv_create_it.
+*
+*  The parameter m specifies the order of B, m > 0.
+*
+*  The formal routine col specifies the matrix B to be factorized. To
+*  obtain j-th column of A the routine fhv_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully computed.
+*
+*  FHV_ESING
+*     The specified matrix is singular within the working precision.
+*
+*  FHV_ECOND
+*     The specified matrix is ill-conditioned.
+*
+*  For more details see comments to the routine luf_factorize.
+*
+*  ALGORITHM
+*
+*  The routine fhv_factorize calls the routine luf_factorize (see the
+*  module GLPLUF), which actually computes LU-factorization of the basis
+*  matrix B in the form
+*
+*     [B] = (F, V, P, Q),
+*
+*  where F and V are such matrices that
+*
+*     B = F * V,
+*
+*  and P and Q are such permutation matrices that the matrix
+*
+*     L = P * F * inv(P)
+*
+*  is lower triangular with unity diagonal, and the matrix
+*
+*     U = P * V * Q
+*
+*  is upper triangular.
+*
+*  In order to build the complete representation of the factorization
+*  (see formula (1) in the file glpfhv.h) the routine fhv_factorize just
+*  additionally sets H = I and P0 = P. */
+
+int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info)
+{     int ret;
+      if (m < 1)
+         xfault("fhv_factorize: m = %d; invalid parameter\n", m);
+      if (m > M_MAX)
+         xfault("fhv_factorize: m = %d; matrix too big\n", m);
+      fhv->m = m;
+      /* invalidate the factorization */
+      fhv->valid = 0;
+      /* allocate/reallocate arrays, if necessary */
+      if (fhv->hh_ind == NULL)
+         fhv->hh_ind = xcalloc(1+fhv->hh_max, sizeof(int));
+      if (fhv->hh_ptr == NULL)
+         fhv->hh_ptr = xcalloc(1+fhv->hh_max, sizeof(int));
+      if (fhv->hh_len == NULL)
+         fhv->hh_len = xcalloc(1+fhv->hh_max, sizeof(int));
+      if (fhv->m_max < m)
+      {  if (fhv->p0_row != NULL) xfree(fhv->p0_row);
+         if (fhv->p0_col != NULL) xfree(fhv->p0_col);
+         if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
+         if (fhv->cc_val != NULL) xfree(fhv->cc_val);
+         fhv->m_max = m + 100;
+         fhv->p0_row = xcalloc(1+fhv->m_max, sizeof(int));
+         fhv->p0_col = xcalloc(1+fhv->m_max, sizeof(int));
+         fhv->cc_ind = xcalloc(1+fhv->m_max, sizeof(int));
+         fhv->cc_val = xcalloc(1+fhv->m_max, sizeof(double));
+      }
+      /* try to factorize the basis matrix */
+      switch (luf_factorize(fhv->luf, m, col, info))
+      {  case 0:
+            break;
+         case LUF_ESING:
+            ret = FHV_ESING;
+            goto done;
+         case LUF_ECOND:
+            ret = FHV_ECOND;
+            goto done;
+         default:
+            xassert(fhv != fhv);
+      }
+      /* the basis matrix has been successfully factorized */
+      fhv->valid = 1;
+      /* H := I */
+      fhv->hh_nfs = 0;
+      /* P0 := P */
+      memcpy(&fhv->p0_row[1], &fhv->luf->pp_row[1], sizeof(int) * m);
+      memcpy(&fhv->p0_col[1], &fhv->luf->pp_col[1], sizeof(int) * m);
+      /* currently H has no factors */
+      fhv->nnz_h = 0;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_h_solve - solve system H*x = b or H'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_h_solve(FHV *fhv, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_h_solve solves either the system H*x = b (if the
+*  flag tr is zero) or the system H'*x = b (if the flag tr is non-zero),
+*  where the matrix H is a component of the factorization specified by
+*  the parameter fhv, H' is a matrix transposed to H.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[m], where m is the order of the
+*  matrix H. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void fhv_h_solve(FHV *fhv, int tr, double x[])
+{     int nfs = fhv->hh_nfs;
+      int *hh_ind = fhv->hh_ind;
+      int *hh_ptr = fhv->hh_ptr;
+      int *hh_len = fhv->hh_len;
+      int *sv_ind = fhv->luf->sv_ind;
+      double *sv_val = fhv->luf->sv_val;
+      int i, k, beg, end, ptr;
+      double temp;
+      if (!fhv->valid)
+         xfault("fhv_h_solve: the factorization is not valid\n");
+      if (!tr)
+      {  /* solve the system H*x = b */
+         for (k = 1; k <= nfs; k++)
+         {  i = hh_ind[k];
+            temp = x[i];
+            beg = hh_ptr[k];
+            end = beg + hh_len[k] - 1;
+            for (ptr = beg; ptr <= end; ptr++)
+               temp -= sv_val[ptr] * x[sv_ind[ptr]];
+            x[i] = temp;
+         }
+      }
+      else
+      {  /* solve the system H'*x = b */
+         for (k = nfs; k >= 1; k--)
+         {  i = hh_ind[k];
+            temp = x[i];
+            if (temp == 0.0) continue;
+            beg = hh_ptr[k];
+            end = beg + hh_len[k] - 1;
+            for (ptr = beg; ptr <= end; ptr++)
+               x[sv_ind[ptr]] -= sv_val[ptr] * temp;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_ftran(FHV *fhv, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void fhv_ftran(FHV *fhv, double x[])
+{     int *pp_row = fhv->luf->pp_row;
+      int *pp_col = fhv->luf->pp_col;
+      int *p0_row = fhv->p0_row;
+      int *p0_col = fhv->p0_col;
+      if (!fhv->valid)
+         xfault("fhv_ftran: the factorization is not valid\n");
+      /* B = F*H*V, therefore inv(B) = inv(V)*inv(H)*inv(F) */
+      fhv->luf->pp_row = p0_row;
+      fhv->luf->pp_col = p0_col;
+      luf_f_solve(fhv->luf, 0, x);
+      fhv->luf->pp_row = pp_row;
+      fhv->luf->pp_col = pp_col;
+      fhv_h_solve(fhv, 0, x);
+      luf_v_solve(fhv->luf, 0, x);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_btran(FHV *fhv, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix B, x is the vector of unknowns to be computed, b is the vector
+*  of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations. */
+
+void fhv_btran(FHV *fhv, double x[])
+{     int *pp_row = fhv->luf->pp_row;
+      int *pp_col = fhv->luf->pp_col;
+      int *p0_row = fhv->p0_row;
+      int *p0_col = fhv->p0_col;
+      if (!fhv->valid)
+         xfault("fhv_btran: the factorization is not valid\n");
+      /* B = F*H*V, therefore inv(B') = inv(F')*inv(H')*inv(V') */
+      luf_v_solve(fhv->luf, 1, x);
+      fhv_h_solve(fhv, 1, x);
+      fhv->luf->pp_row = p0_row;
+      fhv->luf->pp_col = p0_col;
+      luf_f_solve(fhv->luf, 1, x);
+      fhv->luf->pp_row = pp_row;
+      fhv->luf->pp_col = pp_col;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_update_it - update LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_update_it updates the factorization of the basis
+*  matrix B after replacing its j-th column by a new vector.
+*
+*  The parameter j specifies the number of column of B, which has been
+*  replaced, 1 <= j <= m, where m is the order of B.
+*
+*  Row indices and numerical values of non-zero elements of the new
+*  column of B should be placed in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], resp., where len is the number of non-zeros
+*  in the column. Neither zero nor duplicate elements are allowed.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  FHV_ESING
+*     The adjacent basis matrix is structurally singular, since after
+*     changing j-th column of matrix V by the new column (see algorithm
+*     below) the case k1 > k2 occured.
+*
+*  FHV_ECHECK
+*     The factorization is inaccurate, since after transforming k2-th
+*     row of matrix U = P*V*Q, its diagonal element u[k2,k2] is zero or
+*     close to zero,
+*
+*  FHV_ELIMIT
+*     Maximal number of H factors has been reached.
+*
+*  FHV_EROOM
+*     Overflow of the sparse vector area.
+*
+*  In case of non-zero return code the factorization becomes invalid.
+*  It should not be used until it has been recomputed with the routine
+*  fhv_factorize.
+*
+*  ALGORITHM
+*
+*  The routine fhv_update_it is based on the transformation proposed by
+*  Forrest and Tomlin.
+*
+*  Let j-th column of the basis matrix B have been replaced by new
+*  column B[j]. In order to keep the equality B = F*H*V j-th column of
+*  matrix V should be replaced by the column inv(F*H)*B[j].
+*
+*  From the standpoint of matrix U = P*V*Q, replacement of j-th column
+*  of matrix V is equivalent to replacement of k1-th column of matrix U,
+*  where k1 is determined by permutation matrix Q. Thus, matrix U loses
+*  its upper triangular form and becomes the following:
+*
+*         1   k1       k2   m
+*     1   x x * x x x x x x x
+*         . x * x x x x x x x
+*     k1  . . * x x x x x x x
+*         . . * x x x x x x x
+*         . . * . x x x x x x
+*         . . * . . x x x x x
+*         . . * . . . x x x x
+*     k2  . . * . . . . x x x
+*         . . . . . . . . x x
+*     m   . . . . . . . . . x
+*
+*  where row index k2 corresponds to the lowest non-zero element of
+*  k1-th column.
+*
+*  The routine moves rows and columns k1+1, k1+2, ..., k2 of matrix U
+*  by one position to the left and upwards and moves k1-th row and k1-th
+*  column to position k2. As the result of such symmetric permutations
+*  matrix U becomes the following:
+*
+*         1   k1       k2   m
+*     1   x x x x x x x * x x
+*         . x x x x x x * x x
+*     k1  . . x x x x x * x x
+*         . . . x x x x * x x
+*         . . . . x x x * x x
+*         . . . . . x x * x x
+*         . . . . . . x * x x
+*     k2  . . x x x x x * x x
+*         . . . . . . . . x x
+*     m   . . . . . . . . . x
+*
+*  Then the routine performs gaussian elimination to eliminate elements
+*  u[k2,k1], u[k2,k1+1], ..., u[k2,k2-1] using diagonal elements
+*  u[k1,k1], u[k1+1,k1+1], ..., u[k2-1,k2-1] as pivots in the same way
+*  as described in comments to the routine luf_factorize (see the module
+*  GLPLUF). Note that actually all operations are performed on matrix V,
+*  not on matrix U. During the elimination process the routine permutes
+*  neither rows nor columns, so only k2-th row of matrix U is changed.
+*
+*  To keep the main equality B = F*H*V, each time when the routine
+*  applies elementary gaussian transformation to the transformed row of
+*  matrix V (which corresponds to k2-th row of matrix U), it also adds
+*  a new element (gaussian multiplier) to the current row-like factor
+*  of matrix H, which corresponds to the transformed row of matrix V. */
+
+int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
+      const double val[])
+{     int m = fhv->m;
+      LUF *luf = fhv->luf;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      double *vr_piv = luf->vr_piv;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *pp_row = luf->pp_row;
+      int *pp_col = luf->pp_col;
+      int *qq_row = luf->qq_row;
+      int *qq_col = luf->qq_col;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      double *work = luf->work;
+      double eps_tol = luf->eps_tol;
+      int *hh_ind = fhv->hh_ind;
+      int *hh_ptr = fhv->hh_ptr;
+      int *hh_len = fhv->hh_len;
+      int *p0_row = fhv->p0_row;
+      int *p0_col = fhv->p0_col;
+      int *cc_ind = fhv->cc_ind;
+      double *cc_val = fhv->cc_val;
+      double upd_tol = fhv->upd_tol;
+      int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q,
+         p_beg, p_end, p_ptr, ptr, ret;
+      double f, temp;
+      if (!fhv->valid)
+         xfault("fhv_update_it: the factorization is not valid\n");
+      if (!(1 <= j && j <= m))
+         xfault("fhv_update_it: j = %d; column number out of range\n",
+            j);
+      /* check if the new factor of matrix H can be created */
+      if (fhv->hh_nfs == fhv->hh_max)
+      {  /* maximal number of updates has been reached */
+         fhv->valid = 0;
+         ret = FHV_ELIMIT;
+         goto done;
+      }
+      /* convert new j-th column of B to dense format */
+      for (i = 1; i <= m; i++)
+         cc_val[i] = 0.0;
+      for (k = 1; k <= len; k++)
+      {  i = ind[k];
+         if (!(1 <= i && i <= m))
+            xfault("fhv_update_it: ind[%d] = %d; row number out of rang"
+               "e\n", k, i);
+         if (cc_val[i] != 0.0)
+            xfault("fhv_update_it: ind[%d] = %d; duplicate row index no"
+               "t allowed\n", k, i);
+         if (val[k] == 0.0)
+            xfault("fhv_update_it: val[%d] = %g; zero element not allow"
+               "ed\n", k, val[k]);
+         cc_val[i] = val[k];
+      }
+      /* new j-th column of V := inv(F * H) * (new B[j]) */
+      fhv->luf->pp_row = p0_row;
+      fhv->luf->pp_col = p0_col;
+      luf_f_solve(fhv->luf, 0, cc_val);
+      fhv->luf->pp_row = pp_row;
+      fhv->luf->pp_col = pp_col;
+      fhv_h_solve(fhv, 0, cc_val);
+      /* convert new j-th column of V to sparse format */
+      len = 0;
+      for (i = 1; i <= m; i++)
+      {  temp = cc_val[i];
+         if (temp == 0.0 || fabs(temp) < eps_tol) continue;
+         len++, cc_ind[len] = i, cc_val[len] = temp;
+      }
+      /* clear old content of j-th column of matrix V */
+      j_beg = vc_ptr[j];
+      j_end = j_beg + vc_len[j] - 1;
+      for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+      {  /* get row index of v[i,j] */
+         i = sv_ind[j_ptr];
+         /* find v[i,j] in the i-th row */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; sv_ind[i_ptr] != j; i_ptr++) /* nop */;
+         xassert(i_ptr <= i_end);
+         /* remove v[i,j] from the i-th row */
+         sv_ind[i_ptr] = sv_ind[i_end];
+         sv_val[i_ptr] = sv_val[i_end];
+         vr_len[i]--;
+      }
+      /* now j-th column of matrix V is empty */
+      luf->nnz_v -= vc_len[j];
+      vc_len[j] = 0;
+      /* add new elements of j-th column of matrix V to corresponding
+         row lists; determine indices k1 and k2 */
+      k1 = qq_row[j], k2 = 0;
+      for (ptr = 1; ptr <= len; ptr++)
+      {  /* get row index of v[i,j] */
+         i = cc_ind[ptr];
+         /* at least one unused location is needed in i-th row */
+         if (vr_len[i] + 1 > vr_cap[i])
+         {  if (luf_enlarge_row(luf, i, vr_len[i] + 10))
+            {  /* overflow of the sparse vector area */
+               fhv->valid = 0;
+               luf->new_sva = luf->sv_size + luf->sv_size;
+               xassert(luf->new_sva > luf->sv_size);
+               ret = FHV_EROOM;
+               goto done;
+            }
+         }
+         /* add v[i,j] to i-th row */
+         i_ptr = vr_ptr[i] + vr_len[i];
+         sv_ind[i_ptr] = j;
+         sv_val[i_ptr] = cc_val[ptr];
+         vr_len[i]++;
+         /* adjust index k2 */
+         if (k2 < pp_col[i]) k2 = pp_col[i];
+      }
+      /* capacity of j-th column (which is currently empty) should be
+         not less than len locations */
+      if (vc_cap[j] < len)
+      {  if (luf_enlarge_col(luf, j, len))
+         {  /* overflow of the sparse vector area */
+            fhv->valid = 0;
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            ret = FHV_EROOM;
+            goto done;
+         }
+      }
+      /* add new elements of matrix V to j-th column list */
+      j_ptr = vc_ptr[j];
+      memmove(&sv_ind[j_ptr], &cc_ind[1], len * sizeof(int));
+      memmove(&sv_val[j_ptr], &cc_val[1], len * sizeof(double));
+      vc_len[j] = len;
+      luf->nnz_v += len;
+      /* if k1 > k2, diagonal element u[k2,k2] of matrix U is zero and
+         therefore the adjacent basis matrix is structurally singular */
+      if (k1 > k2)
+      {  fhv->valid = 0;
+         ret = FHV_ESING;
+         goto done;
+      }
+      /* perform implicit symmetric permutations of rows and columns of
+         matrix U */
+      i = pp_row[k1], j = qq_col[k1];
+      for (k = k1; k < k2; k++)
+      {  pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k;
+         qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k;
+      }
+      pp_row[k2] = i, pp_col[i] = k2;
+      qq_col[k2] = j, qq_row[j] = k2;
+      /* now i-th row of the matrix V is k2-th row of matrix U; since
+         no pivoting is used, only this row will be transformed */
+      /* copy elements of i-th row of matrix V to the working array and
+         remove these elements from matrix V */
+      for (j = 1; j <= m; j++) work[j] = 0.0;
+      i_beg = vr_ptr[i];
+      i_end = i_beg + vr_len[i] - 1;
+      for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+      {  /* get column index of v[i,j] */
+         j = sv_ind[i_ptr];
+         /* store v[i,j] to the working array */
+         work[j] = sv_val[i_ptr];
+         /* find v[i,j] in the j-th column */
+         j_beg = vc_ptr[j];
+         j_end = j_beg + vc_len[j] - 1;
+         for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++) /* nop */;
+         xassert(j_ptr <= j_end);
+         /* remove v[i,j] from the j-th column */
+         sv_ind[j_ptr] = sv_ind[j_end];
+         sv_val[j_ptr] = sv_val[j_end];
+         vc_len[j]--;
+      }
+      /* now i-th row of matrix V is empty */
+      luf->nnz_v -= vr_len[i];
+      vr_len[i] = 0;
+      /* create the next row-like factor of the matrix H; this factor
+         corresponds to i-th (transformed) row */
+      fhv->hh_nfs++;
+      hh_ind[fhv->hh_nfs] = i;
+      /* hh_ptr[] will be set later */
+      hh_len[fhv->hh_nfs] = 0;
+      /* up to (k2 - k1) free locations are needed to add new elements
+         to the non-trivial row of the row-like factor */
+      if (luf->sv_end - luf->sv_beg < k2 - k1)
+      {  luf_defrag_sva(luf);
+         if (luf->sv_end - luf->sv_beg < k2 - k1)
+         {  /* overflow of the sparse vector area */
+            fhv->valid = luf->valid = 0;
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            ret = FHV_EROOM;
+            goto done;
+         }
+      }
+      /* eliminate subdiagonal elements of matrix U */
+      for (k = k1; k < k2; k++)
+      {  /* v[p,q] = u[k,k] */
+         p = pp_row[k], q = qq_col[k];
+         /* this is the crucial point, where even tiny non-zeros should
+            not be dropped */
+         if (work[q] == 0.0) continue;
+         /* compute gaussian multiplier f = v[i,q] / v[p,q] */
+         f = work[q] / vr_piv[p];
+         /* perform gaussian transformation:
+            (i-th row) := (i-th row) - f * (p-th row)
+            in order to eliminate v[i,q] = u[k2,k] */
+         p_beg = vr_ptr[p];
+         p_end = p_beg + vr_len[p] - 1;
+         for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+            work[sv_ind[p_ptr]] -= f * sv_val[p_ptr];
+         /* store new element (gaussian multiplier that corresponds to
+            p-th row) in the current row-like factor */
+         luf->sv_end--;
+         sv_ind[luf->sv_end] = p;
+         sv_val[luf->sv_end] = f;
+         hh_len[fhv->hh_nfs]++;
+      }
+      /* set pointer to the current row-like factor of the matrix H
+         (if no elements were added to this factor, it is unity matrix
+         and therefore can be discarded) */
+      if (hh_len[fhv->hh_nfs] == 0)
+         fhv->hh_nfs--;
+      else
+      {  hh_ptr[fhv->hh_nfs] = luf->sv_end;
+         fhv->nnz_h += hh_len[fhv->hh_nfs];
+      }
+      /* store new pivot which corresponds to u[k2,k2] */
+      vr_piv[i] = work[qq_col[k2]];
+      /* new elements of i-th row of matrix V (which are non-diagonal
+         elements u[k2,k2+1], ..., u[k2,m] of matrix U = P*V*Q) now are
+         contained in the working array; add them to matrix V */
+      len = 0;
+      for (k = k2+1; k <= m; k++)
+      {  /* get column index and value of v[i,j] = u[k2,k] */
+         j = qq_col[k];
+         temp = work[j];
+         /* if v[i,j] is close to zero, skip it */
+         if (fabs(temp) < eps_tol) continue;
+         /* at least one unused location is needed in j-th column */
+         if (vc_len[j] + 1 > vc_cap[j])
+         {  if (luf_enlarge_col(luf, j, vc_len[j] + 10))
+            {  /* overflow of the sparse vector area */
+               fhv->valid = 0;
+               luf->new_sva = luf->sv_size + luf->sv_size;
+               xassert(luf->new_sva > luf->sv_size);
+               ret = FHV_EROOM;
+               goto done;
+            }
+         }
+         /* add v[i,j] to j-th column */
+         j_ptr = vc_ptr[j] + vc_len[j];
+         sv_ind[j_ptr] = i;
+         sv_val[j_ptr] = temp;
+         vc_len[j]++;
+         /* also store v[i,j] to the auxiliary array */
+         len++, cc_ind[len] = j, cc_val[len] = temp;
+      }
+      /* capacity of i-th row (which is currently empty) should be not
+         less than len locations */
+      if (vr_cap[i] < len)
+      {  if (luf_enlarge_row(luf, i, len))
+         {  /* overflow of the sparse vector area */
+            fhv->valid = 0;
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            ret = FHV_EROOM;
+            goto done;
+         }
+      }
+      /* add new elements to i-th row list */
+      i_ptr = vr_ptr[i];
+      memmove(&sv_ind[i_ptr], &cc_ind[1], len * sizeof(int));
+      memmove(&sv_val[i_ptr], &cc_val[1], len * sizeof(double));
+      vr_len[i] = len;
+      luf->nnz_v += len;
+      /* updating is finished; check that diagonal element u[k2,k2] is
+         not very small in absolute value among other elements in k2-th
+         row and k2-th column of matrix U = P*V*Q */
+      /* temp = max(|u[k2,*]|, |u[*,k2]|) */
+      temp = 0.0;
+      /* walk through k2-th row of U which is i-th row of V */
+      i = pp_row[k2];
+      i_beg = vr_ptr[i];
+      i_end = i_beg + vr_len[i] - 1;
+      for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]);
+      /* walk through k2-th column of U which is j-th column of V */
+      j = qq_col[k2];
+      j_beg = vc_ptr[j];
+      j_end = j_beg + vc_len[j] - 1;
+      for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+         if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]);
+      /* check that u[k2,k2] is not very small */
+      if (fabs(vr_piv[i]) < upd_tol * temp)
+      {  /* the factorization seems to be inaccurate and therefore must
+            be recomputed */
+         fhv->valid = 0;
+         ret = FHV_ECHECK;
+         goto done;
+      }
+      /* the factorization has been successfully updated */
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fhv_delete_it - delete LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpfhv.h"
+*  void fhv_delete_it(FHV *fhv);
+*
+*  DESCRIPTION
+*
+*  The routine fhv_delete_it deletes LP basis factorization specified
+*  by the parameter fhv and frees all memory allocated to this program
+*  object. */
+
+void fhv_delete_it(FHV *fhv)
+{     luf_delete_it(fhv->luf);
+      if (fhv->hh_ind != NULL) xfree(fhv->hh_ind);
+      if (fhv->hh_ptr != NULL) xfree(fhv->hh_ptr);
+      if (fhv->hh_len != NULL) xfree(fhv->hh_len);
+      if (fhv->p0_row != NULL) xfree(fhv->p0_row);
+      if (fhv->p0_col != NULL) xfree(fhv->p0_col);
+      if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
+      if (fhv->cc_val != NULL) xfree(fhv->cc_val);
+      xfree(fhv);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpfhv.h
===================================================================
--- deps/glpk/src/glpfhv.h	(revision 9)
+++ deps/glpk/src/glpfhv.h	(revision 9)
@@ -0,0 +1,170 @@
+/* glpfhv.h (LP basis factorization, FHV eta file version) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPFHV_H
+#define GLPFHV_H
+
+#include "glpluf.h"
+
+/***********************************************************************
+*  The structure FHV defines the factorization of the basis mxm-matrix
+*  B, where m is the number of rows in corresponding problem instance.
+*
+*  This factorization is the following sextet:
+*
+*     [B] = (F, H, V, P0, P, Q),                                     (1)
+*
+*  where F, H, and V are such matrices that
+*
+*     B = F * H * V,                                                 (2)
+*
+*  and P0, P, and Q are such permutation matrices that the matrix
+*
+*     L = P0 * F * inv(P0)                                           (3)
+*
+*  is lower triangular with unity diagonal, and the matrix
+*
+*     U = P * V * Q                                                  (4)
+*
+*  is upper triangular. All the matrices have the same order m, which
+*  is the order of the basis matrix B.
+*
+*  The matrices F, V, P, and Q are stored in the structure LUF (see the
+*  module GLPLUF), which is a member of the structure FHV.
+*
+*  The matrix H is stored in the form of eta file using row-like format
+*  as follows:
+*
+*     H = H[1] * H[2] * ... * H[nfs],                                (5)
+*
+*  where H[k], k = 1, 2, ..., nfs, is a row-like factor, which differs
+*  from the unity matrix only by one row, nfs is current number of row-
+*  like factors. After the factorization has been built for some given
+*  basis matrix B the matrix H has no factors and thus it is the unity
+*  matrix. Then each time when the factorization is recomputed for an
+*  adjacent basis matrix, the next factor H[k], k = 1, 2, ... is built
+*  and added to the end of the eta file H.
+*
+*  Being sparse vectors non-trivial rows of the factors H[k] are stored
+*  in the right part of the sparse vector area (SVA) in the same manner
+*  as rows and columns of the matrix F.
+*
+*  For more details see the program documentation. */
+
+typedef struct FHV FHV;
+
+struct FHV
+{     /* LP basis factorization */
+      int m_max;
+      /* maximal value of m (increased automatically, if necessary) */
+      int m;
+      /* the order of matrices B, F, H, V, P0, P, Q */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      LUF *luf;
+      /* LU-factorization (contains the matrices F, V, P, Q) */
+      /*--------------------------------------------------------------*/
+      /* matrix H in the form of eta file */
+      int hh_max;
+      /* maximal number of row-like factors (which limits the number of
+         updates of the factorization) */
+      int hh_nfs;
+      /* current number of row-like factors (0 <= hh_nfs <= hh_max) */
+      int *hh_ind; /* int hh_ind[1+hh_max]; */
+      /* hh_ind[k], k = 1, ..., nfs, is the number of a non-trivial row
+         of factor H[k] */
+      int *hh_ptr; /* int hh_ptr[1+hh_max]; */
+      /* hh_ptr[k], k = 1, ..., nfs, is a pointer to the first element
+         of the non-trivial row of factor H[k] in the SVA */
+      int *hh_len; /* int hh_len[1+hh_max]; */
+      /* hh_len[k], k = 1, ..., nfs, is the number of non-zero elements
+         in the non-trivial row of factor H[k] */
+      /*--------------------------------------------------------------*/
+      /* matrix P0 */
+      int *p0_row; /* int p0_row[1+m_max]; */
+      /* p0_row[i] = j means that p0[i,j] = 1 */
+      int *p0_col; /* int p0_col[1+m_max]; */
+      /* p0_col[j] = i means that p0[i,j] = 1 */
+      /* if i-th row or column of the matrix F corresponds to i'-th row
+         or column of the matrix L = P0*F*inv(P0), then p0_row[i'] = i
+         and p0_col[i] = i' */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      int *cc_ind; /* int cc_ind[1+m_max]; */
+      /* integer working array */
+      double *cc_val; /* double cc_val[1+m_max]; */
+      /* floating-point working array */
+      /*--------------------------------------------------------------*/
+      /* control parameters */
+      double upd_tol;
+      /* update tolerance; if after updating the factorization absolute
+         value of some diagonal element u[k,k] of matrix U = P*V*Q is
+         less than upd_tol * max(|u[k,*]|, |u[*,k]|), the factorization
+         is considered as inaccurate */
+      /*--------------------------------------------------------------*/
+      /* some statistics */
+      int nnz_h;
+      /* current number of non-zeros in all factors of matrix H */
+};
+
+/* return codes: */
+#define FHV_ESING    1  /* singular matrix */
+#define FHV_ECOND    2  /* ill-conditioned matrix */
+#define FHV_ECHECK   3  /* insufficient accuracy */
+#define FHV_ELIMIT   4  /* update limit reached */
+#define FHV_EROOM    5  /* SVA overflow */
+
+#define fhv_create_it _glp_fhv_create_it
+FHV *fhv_create_it(void);
+/* create LP basis factorization */
+
+#define fhv_factorize _glp_fhv_factorize
+int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info);
+/* compute LP basis factorization */
+
+#define fhv_h_solve _glp_fhv_h_solve
+void fhv_h_solve(FHV *fhv, int tr, double x[]);
+/* solve system H*x = b or H'*x = b */
+
+#define fhv_ftran _glp_fhv_ftran
+void fhv_ftran(FHV *fhv, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+#define fhv_btran _glp_fhv_btran
+void fhv_btran(FHV *fhv, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+#define fhv_update_it _glp_fhv_update_it
+int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
+      const double val[]);
+/* update LP basis factorization */
+
+#define fhv_delete_it _glp_fhv_delete_it
+void fhv_delete_it(FHV *fhv);
+/* delete LP basis factorization */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpgmp.c
===================================================================
--- deps/glpk/src/glpgmp.c	(revision 9)
+++ deps/glpk/src/glpgmp.c	(revision 9)
@@ -0,0 +1,1108 @@
+/* glpgmp.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_STDIO
+#include "glpdmp.h"
+#include "glpgmp.h"
+#define xfault xerror
+
+#ifdef HAVE_GMP               /* use GNU MP bignum library */
+
+int gmp_pool_count(void) { return 0; }
+
+void gmp_free_mem(void) { return; }
+
+#else                         /* use GLPK bignum module */
+
+static DMP *gmp_pool = NULL;
+static int gmp_size = 0;
+static unsigned short *gmp_work = NULL;
+
+void *gmp_get_atom(int size)
+{     if (gmp_pool == NULL)
+         gmp_pool = dmp_create_pool();
+      return dmp_get_atom(gmp_pool, size);
+}
+
+void gmp_free_atom(void *ptr, int size)
+{     xassert(gmp_pool != NULL);
+      dmp_free_atom(gmp_pool, ptr, size);
+      return;
+}
+
+int gmp_pool_count(void)
+{     if (gmp_pool == NULL)
+         return 0;
+      else
+         return dmp_in_use(gmp_pool).lo;
+}
+
+unsigned short *gmp_get_work(int size)
+{     xassert(size > 0);
+      if (gmp_size < size)
+      {  if (gmp_size == 0)
+         {  xassert(gmp_work == NULL);
+            gmp_size = 100;
+         }
+         else
+         {  xassert(gmp_work != NULL);
+            xfree(gmp_work);
+         }
+         while (gmp_size < size) gmp_size += gmp_size;
+         gmp_work = xcalloc(gmp_size, sizeof(unsigned short));
+      }
+      return gmp_work;
+}
+
+void gmp_free_mem(void)
+{     if (gmp_pool != NULL) dmp_delete_pool(gmp_pool);
+      if (gmp_work != NULL) xfree(gmp_work);
+      gmp_pool = NULL;
+      gmp_size = 0;
+      gmp_work = NULL;
+      return;
+}
+
+/*====================================================================*/
+
+mpz_t _mpz_init(void)
+{     /* initialize x, and set its value to 0 */
+      mpz_t x;
+      x = gmp_get_atom(sizeof(struct mpz));
+      x->val = 0;
+      x->ptr = NULL;
+      return x;
+}
+
+void mpz_clear(mpz_t x)
+{     /* free the space occupied by x */
+      mpz_set_si(x, 0);
+      xassert(x->ptr == NULL);
+      /* free the number descriptor */
+      gmp_free_atom(x, sizeof(struct mpz));
+      return;
+}
+
+void mpz_set(mpz_t z, mpz_t x)
+{     /* set the value of z from x */
+      struct mpz_seg *e, *ee, *es;
+      if (z != x)
+      {  mpz_set_si(z, 0);
+         z->val = x->val;
+         xassert(z->ptr == NULL);
+         for (e = x->ptr, es = NULL; e != NULL; e = e->next)
+         {  ee = gmp_get_atom(sizeof(struct mpz_seg));
+            memcpy(ee->d, e->d, 12);
+            ee->next = NULL;
+            if (z->ptr == NULL)
+               z->ptr = ee;
+            else
+               es->next = ee;
+            es = ee;
+         }
+      }
+      return;
+}
+
+void mpz_set_si(mpz_t x, int val)
+{     /* set the value of x to val */
+      struct mpz_seg *e;
+      /* free existing segments, if any */
+      while (x->ptr != NULL)
+      {  e = x->ptr;
+         x->ptr = e->next;
+         gmp_free_atom(e, sizeof(struct mpz_seg));
+      }
+      /* assign new value */
+      if (val == 0x80000000)
+      {  /* long format is needed */
+         x->val = -1;
+         x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg));
+         memset(e->d, 0, 12);
+         e->d[1] = 0x8000;
+         e->next = NULL;
+      }
+      else
+      {  /* short format is enough */
+         x->val = val;
+      }
+      return;
+}
+
+double mpz_get_d(mpz_t x)
+{     /* convert x to a double, truncating if necessary */
+      struct mpz_seg *e;
+      int j;
+      double val, deg;
+      if (x->ptr == NULL)
+         val = (double)x->val;
+      else
+      {  xassert(x->val != 0);
+         val = 0.0;
+         deg = 1.0;
+         for (e = x->ptr; e != NULL; e = e->next)
+         {  for (j = 0; j <= 5; j++)
+            {  val += deg * (double)((int)e->d[j]);
+               deg *= 65536.0;
+            }
+         }
+         if (x->val < 0) val = - val;
+      }
+      return val;
+}
+
+double mpz_get_d_2exp(int *exp, mpz_t x)
+{     /* convert x to a double, truncating if necessary (i.e. rounding
+         towards zero), and returning the exponent separately;
+         the return value is in the range 0.5 <= |d| < 1 and the
+         exponent is stored to *exp; d*2^exp is the (truncated) x value;
+         if x is zero, the return is 0.0 and 0 is stored to *exp;
+         this is similar to the standard C frexp function */
+      struct mpz_seg *e;
+      int j, n, n1;
+      double val;
+      if (x->ptr == NULL)
+         val = (double)x->val, n = 0;
+      else
+      {  xassert(x->val != 0);
+         val = 0.0, n = 0;
+         for (e = x->ptr; e != NULL; e = e->next)
+         {  for (j = 0; j <= 5; j++)
+            {  val += (double)((int)e->d[j]);
+               val /= 65536.0, n += 16;
+            }
+         }
+         if (x->val < 0) val = - val;
+      }
+      val = frexp(val, &n1);
+      *exp = n + n1;
+      return val;
+}
+
+void mpz_swap(mpz_t x, mpz_t y)
+{     /* swap the values x and y efficiently */
+      int val;
+      void *ptr;
+      val = x->val, ptr = x->ptr;
+      x->val = y->val, x->ptr = y->ptr;
+      y->val = val, y->ptr = ptr;
+      return;
+}
+
+static void normalize(mpz_t x)
+{     /* normalize integer x that includes removing non-significant
+         (leading) zeros and converting to short format, if possible */
+      struct mpz_seg *es, *e;
+      /* if the integer is in short format, it remains unchanged */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         goto done;
+      }
+      xassert(x->val == +1 || x->val == -1);
+      /* find the last (most significant) non-zero segment */
+      es = NULL;
+      for (e = x->ptr; e != NULL; e = e->next)
+      {  if (e->d[0] || e->d[1] || e->d[2] ||
+             e->d[3] || e->d[4] || e->d[5]) es = e;
+      }
+      /* if all segments contain zeros, the integer is zero */
+      if (es == NULL)
+      {  mpz_set_si(x, 0);
+         goto done;
+      }
+      /* remove non-significant (leading) zero segments */
+      while (es->next != NULL)
+      {  e = es->next;
+         es->next = e->next;
+         gmp_free_atom(e, sizeof(struct mpz_seg));
+      }
+      /* convert the integer to short format, if possible */
+      e = x->ptr;
+      if (e->next == NULL && e->d[1] <= 0x7FFF &&
+         !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5])
+      {  int val;
+         val = (int)e->d[0] + ((int)e->d[1] << 16);
+         if (x->val < 0) val = - val;
+         mpz_set_si(x, val);
+      }
+done: return;
+}
+
+void mpz_add(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to x + y */
+      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
+      struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee;
+      int k, sx, sy, sz;
+      unsigned int t;
+      /* if [x] = 0 then [z] = [y] */
+      if (x->val == 0)
+      {  xassert(x->ptr == NULL);
+         mpz_set(z, y);
+         goto done;
+      }
+      /* if [y] = 0 then [z] = [x] */
+      if (y->val == 0)
+      {  xassert(y->ptr == NULL);
+         mpz_set(z, x);
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val, zval = x->val + y->val;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         if (!(xval > 0 && yval > 0 && zval <= 0 ||
+               xval < 0 && yval < 0 && zval >= 0))
+         {  mpz_set_si(z, zval);
+            goto done;
+         }
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* main fragment */
+      sz = sx;
+      ez = es = NULL;
+      if (sx > 0 && sy > 0 || sx < 0 && sy < 0)
+      {  /* [x] and [y] have identical signs -- addition */
+         t = 0;
+         for (; ex || ey; ex = ex->next, ey = ey->next)
+         {  if (ex == NULL) ex = &zero;
+            if (ey == NULL) ey = &zero;
+            ee = gmp_get_atom(sizeof(struct mpz_seg));
+            for (k = 0; k <= 5; k++)
+            {  t += (unsigned int)ex->d[k];
+               t += (unsigned int)ey->d[k];
+               ee->d[k] = (unsigned short)t;
+               t >>= 16;
+            }
+            ee->next = NULL;
+            if (ez == NULL)
+               ez = ee;
+            else
+               es->next = ee;
+            es = ee;
+         }
+         if (t)
+         {  /* overflow -- one extra digit is needed */
+            ee = gmp_get_atom(sizeof(struct mpz_seg));
+            ee->d[0] = 1;
+            ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0;
+            ee->next = NULL;
+            xassert(es != NULL);
+            es->next = ee;
+         }
+      }
+      else
+      {  /* [x] and [y] have different signs -- subtraction */
+         t = 1;
+         for (; ex || ey; ex = ex->next, ey = ey->next)
+         {  if (ex == NULL) ex = &zero;
+            if (ey == NULL) ey = &zero;
+            ee = gmp_get_atom(sizeof(struct mpz_seg));
+            for (k = 0; k <= 5; k++)
+            {  t += (unsigned int)ex->d[k];
+               t += (0xFFFF - (unsigned int)ey->d[k]);
+               ee->d[k] = (unsigned short)t;
+               t >>= 16;
+            }
+            ee->next = NULL;
+            if (ez == NULL)
+               ez = ee;
+            else
+               es->next = ee;
+            es = ee;
+         }
+         if (!t)
+         {  /* |[x]| < |[y]| -- result in complement coding */
+            sz = - sz;
+            t = 1;
+            for (ee = ez; ee != NULL; ee = ee->next)
+            for (k = 0; k <= 5; k++)
+            {  t += (0xFFFF - (unsigned int)ee->d[k]);
+               ee->d[k] = (unsigned short)t;
+               t >>= 16;
+            }
+         }
+      }
+      /* contruct and normalize result */
+      mpz_set_si(z, 0);
+      z->val = sz;
+      z->ptr = ez;
+      normalize(z);
+done: return;
+}
+
+void mpz_sub(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to x - y */
+      if (x == y)
+         mpz_set_si(z, 0);
+      else
+      {  y->val = - y->val;
+         mpz_add(z, x, y);
+         if (y != z) y->val = - y->val;
+      }
+      return;
+}
+
+void mpz_mul(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to x * y */
+      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
+      int sx, sy, k, nx, ny, n;
+      unsigned int t;
+      unsigned short *work, *wx, *wy;
+      /* if [x] = 0 then [z] = 0 */
+      if (x->val == 0)
+      {  xassert(x->ptr == NULL);
+         mpz_set_si(z, 0);
+         goto done;
+      }
+      /* if [y] = 0 then [z] = 0 */
+      if (y->val == 0)
+      {  xassert(y->ptr == NULL);
+         mpz_set_si(z, 0);
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val, sz = +1;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         if (xval < 0) xval = - xval, sz = - sz;
+         if (yval < 0) yval = - yval, sz = - sz;
+         if (xval <= 0x7FFFFFFF / yval)
+         {  mpz_set_si(z, sz * (xval * yval));
+            goto done;
+         }
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* determine the number of digits of [x] */
+      nx = n = 0;
+      for (e = ex; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) nx = n;
+      }
+      xassert(nx > 0);
+      /* determine the number of digits of [y] */
+      ny = n = 0;
+      for (e = ey; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) ny = n;
+      }
+      xassert(ny > 0);
+      /* we need working array containing at least nx+ny+ny places */
+      work = gmp_get_work(nx+ny+ny);
+      /* load digits of [x] */
+      wx = &work[0];
+      for (n = 0; n < nx; n++) wx[ny+n] = 0;
+      for (n = 0, e = ex; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wx[ny+n] = e->d[k];
+      /* load digits of [y] */
+      wy = &work[nx+ny];
+      for (n = 0; n < ny; n++) wy[n] = 0;
+      for (n = 0, e = ey; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wy[n] = e->d[k];
+      /* compute [x] * [y] */
+      bigmul(nx, ny, wx, wy);
+      /* construct and normalize result */
+      mpz_set_si(z, 0);
+      z->val = sx * sy;
+      es = NULL;
+      k = 6;
+      for (n = 0; n < nx+ny; n++)
+      {  if (k > 5)
+         {  e = gmp_get_atom(sizeof(struct mpz_seg));
+            e->d[0] = e->d[1] = e->d[2] = 0;
+            e->d[3] = e->d[4] = e->d[5] = 0;
+            e->next = NULL;
+            if (z->ptr == NULL)
+               z->ptr = e;
+            else
+               es->next = e;
+            es = e;
+            k = 0;
+         }
+         es->d[k++] = wx[n];
+      }
+      normalize(z);
+done: return;
+}
+
+void mpz_neg(mpz_t z, mpz_t x)
+{     /* set z to 0 - x */
+      mpz_set(z, x);
+      z->val = - z->val;
+      return;
+}
+
+void mpz_abs(mpz_t z, mpz_t x)
+{     /* set z to the absolute value of x */
+      mpz_set(z, x);
+      if (z->val < 0) z->val = - z->val;
+      return;
+}
+
+void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y)
+{     /* divide x by y, forming quotient q and/or remainder r
+         if q = NULL then quotient is not stored; if r = NULL then
+         remainder is not stored
+         the sign of quotient is determined as in algebra while the
+         sign of remainder is the same as the sign of dividend:
+         +26 : +7 = +3, remainder is +5
+         -26 : +7 = -3, remainder is -5
+         +26 : -7 = -3, remainder is +5
+         -26 : -7 = +3, remainder is -5 */
+      struct mpz_seg dumx, dumy, *ex, *ey, *es, *e;
+      int sx, sy, k, nx, ny, n;
+      unsigned int t;
+      unsigned short *work, *wx, *wy;
+      /* divide by zero is not allowed */
+      if (y->val == 0)
+      {  xassert(y->ptr == NULL);
+         xfault("mpz_div: divide by zero not allowed\n");
+      }
+      /* if [x] = 0 then [q] = [r] = 0 */
+      if (x->val == 0)
+      {  xassert(x->ptr == NULL);
+         if (q != NULL) mpz_set_si(q, 0);
+         if (r != NULL) mpz_set_si(r, 0);
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         if (q != NULL) mpz_set_si(q, xval / yval);
+         if (r != NULL) mpz_set_si(r, xval % yval);
+         goto done;
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* determine the number of digits of [x] */
+      nx = n = 0;
+      for (e = ex; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) nx = n;
+      }
+      xassert(nx > 0);
+      /* determine the number of digits of [y] */
+      ny = n = 0;
+      for (e = ey; e != NULL; e = e->next)
+      for (k = 0; k <= 5; k++)
+      {  n++;
+         if (e->d[k]) ny = n;
+      }
+      xassert(ny > 0);
+      /* if nx < ny then [q] = 0 and [r] = [x] */
+      if (nx < ny)
+      {  if (r != NULL) mpz_set(r, x);
+         if (q != NULL) mpz_set_si(q, 0);
+         goto done;
+      }
+      /* we need working array containing at least nx+ny+1 places */
+      work = gmp_get_work(nx+ny+1);
+      /* load digits of [x] */
+      wx = &work[0];
+      for (n = 0; n < nx; n++) wx[n] = 0;
+      for (n = 0, e = ex; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wx[n] = e->d[k];
+      /* load digits of [y] */
+      wy = &work[nx+1];
+      for (n = 0; n < ny; n++) wy[n] = 0;
+      for (n = 0, e = ey; e != NULL; e = e->next)
+         for (k = 0; k <= 5; k++, n++)
+            if (e->d[k]) wy[n] = e->d[k];
+      /* compute quotient and remainder */
+      xassert(wy[ny-1] != 0);
+      bigdiv(nx-ny, ny, wx, wy);
+      /* construct and normalize quotient */
+      if (q != NULL)
+      {  mpz_set_si(q, 0);
+         q->val = sx * sy;
+         es = NULL;
+         k = 6;
+         for (n = ny; n <= nx; n++)
+         {  if (k > 5)
+            {  e = gmp_get_atom(sizeof(struct mpz_seg));
+               e->d[0] = e->d[1] = e->d[2] = 0;
+               e->d[3] = e->d[4] = e->d[5] = 0;
+               e->next = NULL;
+               if (q->ptr == NULL)
+                  q->ptr = e;
+               else
+                  es->next = e;
+               es = e;
+               k = 0;
+            }
+            es->d[k++] = wx[n];
+         }
+         normalize(q);
+      }
+      /* construct and normalize remainder */
+      if (r != NULL)
+      {  mpz_set_si(r, 0);
+         r->val = sx;
+         es = NULL;
+         k = 6;
+         for (n = 0; n < ny; n++)
+         {  if (k > 5)
+            {  e = gmp_get_atom(sizeof(struct mpz_seg));
+               e->d[0] = e->d[1] = e->d[2] = 0;
+               e->d[3] = e->d[4] = e->d[5] = 0;
+               e->next = NULL;
+               if (r->ptr == NULL)
+                  r->ptr = e;
+               else
+                  es->next = e;
+               es = e;
+               k = 0;
+            }
+            es->d[k++] = wx[n];
+         }
+         normalize(r);
+      }
+done: return;
+}
+
+void mpz_gcd(mpz_t z, mpz_t x, mpz_t y)
+{     /* set z to the greatest common divisor of x and y */
+      /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and,
+         in particular, GCD(0, 0) = 0 */
+      mpz_t u, v, r;
+      mpz_init(u);
+      mpz_init(v);
+      mpz_init(r);
+      mpz_abs(u, x);
+      mpz_abs(v, y);
+      while (mpz_sgn(v))
+      {  mpz_div(NULL, r, u, v);
+         mpz_set(u, v);
+         mpz_set(v, r);
+      }
+      mpz_set(z, u);
+      mpz_clear(u);
+      mpz_clear(v);
+      mpz_clear(r);
+      return;
+}
+
+int mpz_cmp(mpz_t x, mpz_t y)
+{     /* compare x and y; return a positive value if x > y, zero if
+         x = y, or a nefative value if x < y */
+      static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL };
+      struct mpz_seg dumx, dumy, *ex, *ey;
+      int cc, sx, sy, k;
+      unsigned int t;
+      if (x == y)
+      {  cc = 0;
+         goto done;
+      }
+      /* special case when both [x] and [y] are in short format */
+      if (x->ptr == NULL && y->ptr == NULL)
+      {  int xval = x->val, yval = y->val;
+         xassert(xval != 0x80000000 && yval != 0x80000000);
+         cc = (xval > yval ? +1 : xval < yval ? -1 : 0);
+         goto done;
+      }
+      /* special case when [x] and [y] have different signs */
+      if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0)
+      {  cc = +1;
+         goto done;
+      }
+      if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0)
+      {  cc = -1;
+         goto done;
+      }
+      /* convert [x] to long format, if necessary */
+      if (x->ptr == NULL)
+      {  xassert(x->val != 0x80000000);
+         if (x->val >= 0)
+         {  sx = +1;
+            t = (unsigned int)(+ x->val);
+         }
+         else
+         {  sx = -1;
+            t = (unsigned int)(- x->val);
+         }
+         ex = &dumx;
+         ex->d[0] = (unsigned short)t;
+         ex->d[1] = (unsigned short)(t >> 16);
+         ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0;
+         ex->next = NULL;
+      }
+      else
+      {  sx = x->val;
+         xassert(sx == +1 || sx == -1);
+         ex = x->ptr;
+      }
+      /* convert [y] to long format, if necessary */
+      if (y->ptr == NULL)
+      {  xassert(y->val != 0x80000000);
+         if (y->val >= 0)
+         {  sy = +1;
+            t = (unsigned int)(+ y->val);
+         }
+         else
+         {  sy = -1;
+            t = (unsigned int)(- y->val);
+         }
+         ey = &dumy;
+         ey->d[0] = (unsigned short)t;
+         ey->d[1] = (unsigned short)(t >> 16);
+         ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0;
+         ey->next = NULL;
+      }
+      else
+      {  sy = y->val;
+         xassert(sy == +1 || sy == -1);
+         ey = y->ptr;
+      }
+      /* main fragment */
+      xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0);
+      cc = 0;
+      for (; ex || ey; ex = ex->next, ey = ey->next)
+      {  if (ex == NULL) ex = &zero;
+         if (ey == NULL) ey = &zero;
+         for (k = 0; k <= 5; k++)
+         {  if (ex->d[k] > ey->d[k]) cc = +1;
+            if (ex->d[k] < ey->d[k]) cc = -1;
+         }
+      }
+      if (sx < 0) cc = - cc;
+done: return cc;
+}
+
+int mpz_sgn(mpz_t x)
+{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+      int s;
+      s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0);
+      return s;
+}
+
+int mpz_out_str(void *_fp, int base, mpz_t x)
+{     /* output x on stream fp, as a string in given base; the base
+         may vary from 2 to 36;
+         return the number of bytes written, or if an error occurred,
+         return 0 */
+      FILE *fp = _fp;
+      mpz_t b, y, r;
+      int n, j, nwr = 0;
+      unsigned char *d;
+      static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+      if (!(2 <= base && base <= 36))
+         xfault("mpz_out_str: base = %d; invalid base\n", base);
+      mpz_init(b);
+      mpz_set_si(b, base);
+      mpz_init(y);
+      mpz_init(r);
+      /* determine the number of digits */
+      mpz_abs(y, x);
+      for (n = 0; mpz_sgn(y) != 0; n++)
+         mpz_div(y, NULL, y, b);
+      if (n == 0) n = 1;
+      /* compute the digits */
+      d = xmalloc(n);
+      mpz_abs(y, x);
+      for (j = 0; j < n; j++)
+      {  mpz_div(y, r, y, b);
+         xassert(0 <= r->val && r->val < base && r->ptr == NULL);
+         d[j] = (unsigned char)r->val;
+      }
+      /* output the integer to the stream */
+      if (fp == NULL) fp = stdout;
+      if (mpz_sgn(x) < 0)
+         fputc('-', fp), nwr++;
+      for (j = n-1; j >= 0; j--)
+         fputc(set[d[j]], fp), nwr++;
+      if (ferror(fp)) nwr = 0;
+      mpz_clear(b);
+      mpz_clear(y);
+      mpz_clear(r);
+      xfree(d);
+      return nwr;
+}
+
+/*====================================================================*/
+
+mpq_t _mpq_init(void)
+{     /* initialize x, and set its value to 0/1 */
+      mpq_t x;
+      x = gmp_get_atom(sizeof(struct mpq));
+      x->p.val = 0;
+      x->p.ptr = NULL;
+      x->q.val = 1;
+      x->q.ptr = NULL;
+      return x;
+}
+
+void mpq_clear(mpq_t x)
+{     /* free the space occupied by x */
+      mpz_set_si(&x->p, 0);
+      xassert(x->p.ptr == NULL);
+      mpz_set_si(&x->q, 0);
+      xassert(x->q.ptr == NULL);
+      /* free the number descriptor */
+      gmp_free_atom(x, sizeof(struct mpq));
+      return;
+}
+
+void mpq_canonicalize(mpq_t x)
+{     /* remove any factors that are common to the numerator and
+         denominator of x, and make the denominator positive */
+      mpz_t f;
+      xassert(x->q.val != 0);
+      if (x->q.val < 0)
+      {  mpz_neg(&x->p, &x->p);
+         mpz_neg(&x->q, &x->q);
+      }
+      mpz_init(f);
+      mpz_gcd(f, &x->p, &x->q);
+      if (!(f->val == 1 && f->ptr == NULL))
+      {  mpz_div(&x->p, NULL, &x->p, f);
+         mpz_div(&x->q, NULL, &x->q, f);
+      }
+      mpz_clear(f);
+      return;
+}
+
+void mpq_set(mpq_t z, mpq_t x)
+{     /* set the value of z from x */
+      if (z != x)
+      {  mpz_set(&z->p, &x->p);
+         mpz_set(&z->q, &x->q);
+      }
+      return;
+}
+
+void mpq_set_si(mpq_t x, int p, unsigned int q)
+{     /* set the value of x to p/q */
+      if (q == 0)
+         xfault("mpq_set_si: zero denominator not allowed\n");
+      mpz_set_si(&x->p, p);
+      xassert(q <= 0x7FFFFFFF);
+      mpz_set_si(&x->q, q);
+      return;
+}
+
+double mpq_get_d(mpq_t x)
+{     /* convert x to a double, truncating if necessary */
+      int np, nq;
+      double p, q;
+      p = mpz_get_d_2exp(&np, &x->p);
+      q = mpz_get_d_2exp(&nq, &x->q);
+      return ldexp(p / q, np - nq);
+}
+
+void mpq_set_d(mpq_t x, double val)
+{     /* set x to val; there is no rounding, the conversion is exact */
+      int s, n, d, j;
+      double f;
+      mpz_t temp;
+      xassert(-DBL_MAX <= val && val <= +DBL_MAX);
+      mpq_set_si(x, 0, 1);
+      if (val > 0.0)
+         s = +1;
+      else if (val < 0.0)
+         s = -1;
+      else
+         goto done;
+      f = frexp(fabs(val), &n);
+      /* |val| = f * 2^n, where 0.5 <= f < 1.0 */
+      mpz_init(temp);
+      while (f != 0.0)
+      {  f *= 16.0, n -= 4;
+         d = (int)f;
+         xassert(0 <= d && d <= 15);
+         f -= (double)d;
+         /* x := 16 * x + d */
+         mpz_set_si(temp, 16);
+         mpz_mul(&x->p, &x->p, temp);
+         mpz_set_si(temp, d);
+         mpz_add(&x->p, &x->p, temp);
+      }
+      mpz_clear(temp);
+      /* x := x * 2^n */
+      if (n > 0)
+      {  for (j = 1; j <= n; j++)
+            mpz_add(&x->p, &x->p, &x->p);
+      }
+      else if (n < 0)
+      {  for (j = 1; j <= -n; j++)
+            mpz_add(&x->q, &x->q, &x->q);
+         mpq_canonicalize(x);
+      }
+      if (s < 0) mpq_neg(x, x);
+done: return;
+}
+
+void mpq_add(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x + y */
+      mpz_t p, q;
+      mpz_init(p);
+      mpz_init(q);
+      mpz_mul(p, &x->p, &y->q);
+      mpz_mul(q, &x->q, &y->p);
+      mpz_add(p, p, q);
+      mpz_mul(q, &x->q, &y->q);
+      mpz_set(&z->p, p);
+      mpz_set(&z->q, q);
+      mpz_clear(p);
+      mpz_clear(q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_sub(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x - y */
+      mpz_t p, q;
+      mpz_init(p);
+      mpz_init(q);
+      mpz_mul(p, &x->p, &y->q);
+      mpz_mul(q, &x->q, &y->p);
+      mpz_sub(p, p, q);
+      mpz_mul(q, &x->q, &y->q);
+      mpz_set(&z->p, p);
+      mpz_set(&z->q, q);
+      mpz_clear(p);
+      mpz_clear(q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_mul(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x * y */
+      mpz_mul(&z->p, &x->p, &y->p);
+      mpz_mul(&z->q, &x->q, &y->q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_div(mpq_t z, mpq_t x, mpq_t y)
+{     /* set z to x / y */
+      mpz_t p, q;
+      if (mpq_sgn(y) == 0)
+         xfault("mpq_div: zero divisor not allowed\n");
+      mpz_init(p);
+      mpz_init(q);
+      mpz_mul(p, &x->p, &y->q);
+      mpz_mul(q, &x->q, &y->p);
+      mpz_set(&z->p, p);
+      mpz_set(&z->q, q);
+      mpz_clear(p);
+      mpz_clear(q);
+      mpq_canonicalize(z);
+      return;
+}
+
+void mpq_neg(mpq_t z, mpq_t x)
+{     /* set z to 0 - x */
+      mpq_set(z, x);
+      mpz_neg(&z->p, &z->p);
+      return;
+}
+
+void mpq_abs(mpq_t z, mpq_t x)
+{     /* set z to the absolute value of x */
+      mpq_set(z, x);
+      mpz_abs(&z->p, &z->p);
+      xassert(mpz_sgn(&x->q) > 0);
+      return;
+}
+
+int mpq_cmp(mpq_t x, mpq_t y)
+{     /* compare x and y; return a positive value if x > y, zero if
+         x = y, or a nefative value if x < y */
+      mpq_t temp;
+      int s;
+      mpq_init(temp);
+      mpq_sub(temp, x, y);
+      s = mpq_sgn(temp);
+      mpq_clear(temp);
+      return s;
+}
+
+int mpq_sgn(mpq_t x)
+{     /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */
+      int s;
+      s = mpz_sgn(&x->p);
+      xassert(mpz_sgn(&x->q) > 0);
+      return s;
+}
+
+int mpq_out_str(void *_fp, int base, mpq_t x)
+{     /* output x on stream fp, as a string in given base; the base
+         may vary from 2 to 36; output is in the form 'num/den' or if
+         the denominator is 1 then just 'num';
+         if the parameter fp is a null pointer, stdout is assumed;
+         return the number of bytes written, or if an error occurred,
+         return 0 */
+      FILE *fp = _fp;
+      int nwr;
+      if (!(2 <= base && base <= 36))
+         xfault("mpq_out_str: base = %d; invalid base\n", base);
+      if (fp == NULL) fp = stdout;
+      nwr = mpz_out_str(fp, base, &x->p);
+      if (x->q.val == 1 && x->q.ptr == NULL)
+         ;
+      else
+      {  fputc('/', fp), nwr++;
+         nwr += mpz_out_str(fp, base, &x->q);
+      }
+      if (ferror(fp)) nwr = 0;
+      return nwr;
+}
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpgmp.h
===================================================================
--- deps/glpk/src/glpgmp.h	(revision 9)
+++ deps/glpk/src/glpgmp.h	(revision 9)
@@ -0,0 +1,190 @@
+/* glpgmp.h (bignum arithmetic) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPGMP_H
+#define GLPGMP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_GMP               /* use GNU MP bignum library */
+
+#include <gmp.h>
+
+#define gmp_pool_count        _glp_gmp_pool_count
+#define gmp_free_mem          _glp_gmp_free_mem
+
+int gmp_pool_count(void);
+void gmp_free_mem(void);
+
+#else                         /* use GLPK bignum module */
+
+/*----------------------------------------------------------------------
+// INTEGER NUMBERS
+//
+// Depending on its magnitude an integer number of arbitrary precision
+// is represented either in short format or in long format.
+//
+// Short format corresponds to the int type and allows representing
+// integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for
+// the most negative number of int type the short format is not used.
+//
+// In long format integer numbers are represented using the positional
+// system with the base (radix) 2^16 = 65536:
+//
+//    x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j,
+//
+// where x is the integer to be represented, s is its sign (+1 or -1),
+// d[j] are its digits (0 <= d[j] <= 65535).
+//
+// RATIONAL NUMBERS
+//
+// A rational number is represented as an irreducible fraction:
+//
+//    p / q,
+//
+// where p (numerator) and q (denominator) are integer numbers (q > 0)
+// having no common divisors. */
+
+struct mpz
+{     /* integer number */
+      int val;
+      /* if ptr is a null pointer, the number is in short format, and
+         val is its value; otherwise, the number is in long format, and
+         val is its sign (+1 or -1) */
+      struct mpz_seg *ptr;
+      /* pointer to the linked list of the number segments ordered in
+         ascending of powers of the base */
+};
+
+struct mpz_seg
+{     /* integer number segment */
+      unsigned short d[6];
+      /* six digits of the number ordered in ascending of powers of the
+         base */
+      struct mpz_seg *next;
+      /* pointer to the next number segment */
+};
+
+struct mpq
+{     /* rational number (p / q) */
+      struct mpz p;
+      /* numerator */
+      struct mpz q;
+      /* denominator */
+};
+
+typedef struct mpz *mpz_t;
+typedef struct mpq *mpq_t;
+
+#define gmp_get_atom          _glp_gmp_get_atom
+#define gmp_free_atom         _glp_gmp_free_atom
+#define gmp_pool_count        _glp_gmp_pool_count
+#define gmp_get_work          _glp_gmp_get_work
+#define gmp_free_mem          _glp_gmp_free_mem
+
+#define _mpz_init             _glp_mpz_init
+#define mpz_clear             _glp_mpz_clear
+#define mpz_set               _glp_mpz_set
+#define mpz_set_si            _glp_mpz_set_si
+#define mpz_get_d             _glp_mpz_get_d
+#define mpz_get_d_2exp        _glp_mpz_get_d_2exp
+#define mpz_swap              _glp_mpz_swap
+#define mpz_add               _glp_mpz_add
+#define mpz_sub               _glp_mpz_sub
+#define mpz_mul               _glp_mpz_mul
+#define mpz_neg               _glp_mpz_neg
+#define mpz_abs               _glp_mpz_abs
+#define mpz_div               _glp_mpz_div
+#define mpz_gcd               _glp_mpz_gcd
+#define mpz_cmp               _glp_mpz_cmp
+#define mpz_sgn               _glp_mpz_sgn
+#define mpz_out_str           _glp_mpz_out_str
+
+#define _mpq_init             _glp_mpq_init
+#define mpq_clear             _glp_mpq_clear
+#define mpq_canonicalize      _glp_mpq_canonicalize
+#define mpq_set               _glp_mpq_set
+#define mpq_set_si            _glp_mpq_set_si
+#define mpq_get_d             _glp_mpq_get_d
+#define mpq_set_d             _glp_mpq_set_d
+#define mpq_add               _glp_mpq_add
+#define mpq_sub               _glp_mpq_sub
+#define mpq_mul               _glp_mpq_mul
+#define mpq_div               _glp_mpq_div
+#define mpq_neg               _glp_mpq_neg
+#define mpq_abs               _glp_mpq_abs
+#define mpq_cmp               _glp_mpq_cmp
+#define mpq_sgn               _glp_mpq_sgn
+#define mpq_out_str           _glp_mpq_out_str
+
+void *gmp_get_atom(int size);
+void gmp_free_atom(void *ptr, int size);
+int gmp_pool_count(void);
+unsigned short *gmp_get_work(int size);
+void gmp_free_mem(void);
+
+mpz_t _mpz_init(void);
+#define mpz_init(x) (void)((x) = _mpz_init())
+void mpz_clear(mpz_t x);
+void mpz_set(mpz_t z, mpz_t x);
+void mpz_set_si(mpz_t x, int val);
+double mpz_get_d(mpz_t x);
+double mpz_get_d_2exp(int *exp, mpz_t x);
+void mpz_swap(mpz_t x, mpz_t y);
+void mpz_add(mpz_t, mpz_t, mpz_t);
+void mpz_sub(mpz_t, mpz_t, mpz_t);
+void mpz_mul(mpz_t, mpz_t, mpz_t);
+void mpz_neg(mpz_t z, mpz_t x);
+void mpz_abs(mpz_t z, mpz_t x);
+void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y);
+void mpz_gcd(mpz_t z, mpz_t x, mpz_t y);
+int mpz_cmp(mpz_t x, mpz_t y);
+int mpz_sgn(mpz_t x);
+int mpz_out_str(void *fp, int base, mpz_t x);
+
+mpq_t _mpq_init(void);
+#define mpq_init(x) (void)((x) = _mpq_init())
+void mpq_clear(mpq_t x);
+void mpq_canonicalize(mpq_t x);
+void mpq_set(mpq_t z, mpq_t x);
+void mpq_set_si(mpq_t x, int p, unsigned int q);
+double mpq_get_d(mpq_t x);
+void mpq_set_d(mpq_t x, double val);
+void mpq_add(mpq_t z, mpq_t x, mpq_t y);
+void mpq_sub(mpq_t z, mpq_t x, mpq_t y);
+void mpq_mul(mpq_t z, mpq_t x, mpq_t y);
+void mpq_div(mpq_t z, mpq_t x, mpq_t y);
+void mpq_neg(mpq_t z, mpq_t x);
+void mpq_abs(mpq_t z, mpq_t x);
+int mpq_cmp(mpq_t x, mpq_t y);
+int mpq_sgn(mpq_t x);
+int mpq_out_str(void *fp, int base, mpq_t x);
+
+#endif
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glphbm.c
===================================================================
--- deps/glpk/src/glphbm.c	(revision 9)
+++ deps/glpk/src/glphbm.c	(revision 9)
@@ -0,0 +1,519 @@
+/* glphbm.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glphbm.h"
+#include "glpenv.h"
+
+/***********************************************************************
+*  NAME
+*
+*  hbm_read_mat - read sparse matrix in Harwell-Boeing format
+*
+*  SYNOPSIS
+*
+*  #include "glphbm.h"
+*  HBM *hbm_read_mat(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing
+*  format from a text file whose name is the character string fname.
+*
+*  Detailed description of the Harwell-Boeing format recognised by this
+*  routine is given in the following report:
+*
+*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
+*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
+*
+*  RETURNS
+*
+*  If no error occured, the routine hbm_read_mat returns a pointer to
+*  a data structure containing the matrix. In case of error the routine
+*  prints an appropriate error message and returns NULL. */
+
+struct dsa
+{     /* working area used by routine hbm_read_mat */
+      const char *fname;
+      /* name of input text file */
+      FILE *fp;
+      /* stream assigned to input text file */
+      int seqn;
+      /* card sequential number */
+      char card[80+1];
+      /* card image buffer */
+      int fmt_p;
+      /* scale factor */
+      int fmt_k;
+      /* iterator */
+      int fmt_f;
+      /* format code */
+      int fmt_w;
+      /* field width */
+      int fmt_d;
+      /* number of decimal places after point */
+};
+
+/***********************************************************************
+*  read_card - read next data card
+*
+*  This routine reads the next 80-column card from the input text file
+*  and stores its image into the character string card. If the card was
+*  read successfully, the routine returns zero, otherwise non-zero. */
+
+static int read_card(struct dsa *dsa)
+{     int k, c;
+      dsa->seqn++;
+      memset(dsa->card, ' ', 80), dsa->card[80] = '\0';
+      k = 0;
+      for (;;)
+      {  c = fgetc(dsa->fp);
+         if (ferror(dsa->fp))
+         {  xprintf("%s:%d: read error - %s\n", dsa->fname, dsa->seqn,
+               strerror(errno));
+            return 1;
+         }
+         if (feof(dsa->fp))
+         {  if (k == 0)
+               xprintf("%s:%d: unexpected EOF\n", dsa->fname,
+                  dsa->seqn);
+            else
+               xprintf("%s:%d: missing final LF\n", dsa->fname,
+                  dsa->seqn);
+            return 1;
+         }
+         if (c == '\r') continue;
+         if (c == '\n') break;
+         if (iscntrl(c))
+         {  xprintf("%s:%d: invalid control character 0x%02X\n",
+               dsa->fname, dsa->seqn, c);
+            return 1;
+         }
+         if (k == 80)
+         {  xprintf("%s:%d: card image too long\n", dsa->fname,
+               dsa->seqn);
+            return 1;
+         }
+         dsa->card[k++] = (char)c;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  scan_int - scan integer value from the current card
+*
+*  This routine scans an integer value from the current card, where fld
+*  is the name of the field, pos is the position of the field, width is
+*  the width of the field, val points to a location to which the scanned
+*  value should be stored. If the value was scanned successfully, the
+*  routine returns zero, otherwise non-zero. */
+
+static int scan_int(struct dsa *dsa, char *fld, int pos, int width,
+      int *val)
+{     char str[80+1];
+      xassert(1 <= width && width <= 80);
+      memcpy(str, dsa->card + pos, width), str[width] = '\0';
+      if (str2int(strspx(str), val))
+      {  xprintf("%s:%d: field `%s' contains invalid value `%s'\n",
+            dsa->fname, dsa->seqn, fld, str);
+         return 1;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  parse_fmt - parse Fortran format specification
+*
+*  This routine parses the Fortran format specification represented as
+*  character string which fmt points to and stores format elements into
+*  appropriate static locations. Should note that not all valid Fortran
+*  format specifications may be recognised. If the format specification
+*  was recognised, the routine returns zero, otherwise non-zero. */
+
+static int parse_fmt(struct dsa *dsa, char *fmt)
+{     int k, s, val;
+      char str[80+1];
+      /* first character should be left parenthesis */
+      if (fmt[0] != '(')
+fail: {  xprintf("hbm_read_mat: format `%s' not recognised\n", fmt);
+         return 1;
+      }
+      k = 1;
+      /* optional scale factor */
+      dsa->fmt_p = 0;
+      if (isdigit((unsigned char)fmt[k]))
+      {  s = 0;
+         while (isdigit((unsigned char)fmt[k]))
+         {  if (s == 80) goto fail;
+            str[s++] = fmt[k++];
+         }
+         str[s] = '\0';
+         if (str2int(str, &val)) goto fail;
+         if (toupper((unsigned char)fmt[k]) != 'P') goto iter;
+         dsa->fmt_p = val, k++;
+         if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail;
+         /* optional comma may follow scale factor */
+         if (fmt[k] == ',') k++;
+      }
+      /* optional iterator */
+      dsa->fmt_k = 1;
+      if (isdigit((unsigned char)fmt[k]))
+      {  s = 0;
+         while (isdigit((unsigned char)fmt[k]))
+         {  if (s == 80) goto fail;
+            str[s++] = fmt[k++];
+         }
+         str[s] = '\0';
+         if (str2int(str, &val)) goto fail;
+iter:    dsa->fmt_k = val;
+         if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail;
+      }
+      /* format code */
+      dsa->fmt_f = toupper((unsigned char)fmt[k++]);
+      if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' ||
+            dsa->fmt_f == 'F' || dsa->fmt_f == 'G' ||
+            dsa->fmt_f == 'I')) goto fail;
+      /* field width */
+      if (!isdigit((unsigned char)fmt[k])) goto fail;
+      s = 0;
+      while (isdigit((unsigned char)fmt[k]))
+      {  if (s == 80) goto fail;
+         str[s++] = fmt[k++];
+      }
+      str[s] = '\0';
+      if (str2int(str, &dsa->fmt_w)) goto fail;
+      if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail;
+      /* optional number of decimal places after point */
+      dsa->fmt_d = 0;
+      if (fmt[k] == '.')
+      {  k++;
+         if (!isdigit((unsigned char)fmt[k])) goto fail;
+         s = 0;
+         while (isdigit((unsigned char)fmt[k]))
+         {  if (s == 80) goto fail;
+            str[s++] = fmt[k++];
+         }
+         str[s] = '\0';
+         if (str2int(str, &dsa->fmt_d)) goto fail;
+         if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail;
+      }
+      /* last character should be right parenthesis */
+      if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail;
+      return 0;
+}
+
+/***********************************************************************
+*  read_int_array - read array of integer type
+*
+*  This routine reads an integer array from the input text file, where
+*  name is array name, fmt is Fortran format specification that controls
+*  reading, n is number of array elements, val is array of integer type.
+*  If the array was read successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int read_int_array(struct dsa *dsa, char *name, char *fmt,
+      int n, int val[])
+{     int k, pos;
+      char str[80+1];
+      if (parse_fmt(dsa, fmt)) return 1;
+      if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 &&
+            dsa->fmt_k * dsa->fmt_w <= 80))
+      {  xprintf(
+            "%s:%d: can't read array `%s' - invalid format `%s'\n",
+            dsa->fname, dsa->seqn, name, fmt);
+         return 1;
+      }
+      for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
+      {  if (pos >= dsa->fmt_k)
+         {  if (read_card(dsa)) return 1;
+            pos = 0;
+         }
+         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
+         str[dsa->fmt_w] = '\0';
+         strspx(str);
+         if (str2int(str, &val[k]))
+         {  xprintf(
+               "%s:%d: can't read array `%s' - invalid value `%s'\n",
+               dsa->fname, dsa->seqn, name, str);
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  read_real_array - read array of real type
+*
+*  This routine reads a real array from the input text file, where name
+*  is array name, fmt is Fortran format specification that controls
+*  reading, n is number of array elements, val is array of real type.
+*  If the array was read successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int read_real_array(struct dsa *dsa, char *name, char *fmt,
+      int n, double val[])
+{     int k, pos;
+      char str[80+1], *ptr;
+      if (parse_fmt(dsa, fmt)) return 1;
+      if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 &&
+            dsa->fmt_k * dsa->fmt_w <= 80))
+      {  xprintf(
+            "%s:%d: can't read array `%s' - invalid format `%s'\n",
+            dsa->fname, dsa->seqn, name, fmt);
+         return 1;
+      }
+      for (k = 1, pos = INT_MAX; k <= n; k++, pos++)
+      {  if (pos >= dsa->fmt_k)
+         {  if (read_card(dsa)) return 1;
+            pos = 0;
+         }
+         memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w);
+         str[dsa->fmt_w] = '\0';
+         strspx(str);
+         if (strchr(str, '.') == NULL && strcmp(str, "0"))
+         {  xprintf("%s(%d): can't read array `%s' - value `%s' has no "
+               "decimal point\n", dsa->fname, dsa->seqn, name, str);
+            return 1;
+         }
+         /* sometimes lower case letters appear */
+         for (ptr = str; *ptr; ptr++)
+            *ptr = (char)toupper((unsigned char)*ptr);
+         ptr = strchr(str, 'D');
+         if (ptr != NULL) *ptr = 'E';
+         /* value may appear with decimal exponent but without letters
+            E or D (for example, -123.456-012), so missing letter should
+            be inserted */
+         ptr = strchr(str+1, '+');
+         if (ptr == NULL) ptr = strchr(str+1, '-');
+         if (ptr != NULL && *(ptr-1) != 'E')
+         {  xassert(strlen(str) < 80);
+            memmove(ptr+1, ptr, strlen(ptr)+1);
+            *ptr = 'E';
+         }
+         if (str2num(str, &val[k]))
+         {  xprintf(
+               "%s:%d: can't read array `%s' - invalid value `%s'\n",
+               dsa->fname, dsa->seqn, name, str);
+            return 1;
+         }
+      }
+      return 0;
+}
+
+HBM *hbm_read_mat(const char *fname)
+{     struct dsa _dsa, *dsa = &_dsa;
+      HBM *hbm = NULL;
+      dsa->fname = fname;
+      xprintf("hbm_read_mat: reading matrix from `%s'...\n",
+         dsa->fname);
+      dsa->fp = fopen(dsa->fname, "r");
+      if (dsa->fp == NULL)
+      {  xprintf("hbm_read_mat: unable to open `%s' - %s\n",
+            dsa->fname, strerror(errno));
+         goto fail;
+      }
+      dsa->seqn = 0;
+      hbm = xmalloc(sizeof(HBM));
+      memset(hbm, 0, sizeof(HBM));
+      /* read the first heading card */
+      if (read_card(dsa)) goto fail;
+      memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0';
+      strtrim(hbm->title);
+      xprintf("%s\n", hbm->title);
+      memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0';
+      strspx(hbm->key);
+      xprintf("key = %s\n", hbm->key);
+      /* read the second heading card */
+      if (read_card(dsa)) goto fail;
+      if (scan_int(dsa, "totcrd",  0, 14, &hbm->totcrd)) goto fail;
+      if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail;
+      if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail;
+      if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail;
+      if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail;
+      xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc"
+         "rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd,
+         hbm->valcrd, hbm->rhscrd);
+      /* read the third heading card */
+      if (read_card(dsa)) goto fail;
+      memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0';
+      if (strchr("RCP",   hbm->mxtype[0]) == NULL ||
+          strchr("SUHZR", hbm->mxtype[1]) == NULL ||
+          strchr("AE",    hbm->mxtype[2]) == NULL)
+      {  xprintf("%s:%d: matrix type `%s' not recognised\n",
+            dsa->fname, dsa->seqn, hbm->mxtype);
+         goto fail;
+      }
+      if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail;
+      if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail;
+      if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail;
+      if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail;
+      xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl ="
+         " %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero,
+         hbm->neltvl);
+      /* read the fourth heading card */
+      if (read_card(dsa)) goto fail;
+      memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0';
+      strspx(hbm->ptrfmt);
+      memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0';
+      strspx(hbm->indfmt);
+      memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0';
+      strspx(hbm->valfmt);
+      memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0';
+      strspx(hbm->rhsfmt);
+      xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n",
+         hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt);
+      /* read the fifth heading card (optional) */
+      if (hbm->rhscrd <= 0)
+      {  strcpy(hbm->rhstyp, "???");
+         hbm->nrhs = 0;
+         hbm->nrhsix = 0;
+      }
+      else
+      {  if (read_card(dsa)) goto fail;
+         memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0';
+         if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail;
+         if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail;
+         xprintf("rhstyp = `%s'; nrhs = %d; nrhsix = %d\n",
+            hbm->rhstyp, hbm->nrhs, hbm->nrhsix);
+      }
+      /* read matrix structure */
+      hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int));
+      if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1,
+         hbm->colptr)) goto fail;
+      hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int));
+      if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero,
+         hbm->rowind)) goto fail;
+      /* read matrix values */
+      if (hbm->valcrd <= 0) goto done;
+      if (hbm->mxtype[2] == 'A')
+      {  /* assembled matrix */
+         hbm->values = xcalloc(1+hbm->nnzero, sizeof(double));
+         if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero,
+            hbm->values)) goto fail;
+      }
+      else
+      {  /* elemental (unassembled) matrix */
+         hbm->values = xcalloc(1+hbm->neltvl, sizeof(double));
+         if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl,
+            hbm->values)) goto fail;
+      }
+      /* read right-hand sides */
+      if (hbm->nrhs <= 0) goto done;
+      if (hbm->rhstyp[0] == 'F')
+      {  /* dense format */
+         hbm->nrhsvl = hbm->nrow * hbm->nrhs;
+         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
+         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
+            hbm->rhsval)) goto fail;
+      }
+      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A')
+      {  /* sparse format */
+         /* read pointers */
+         hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int));
+         if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1,
+            hbm->rhsptr)) goto fail;
+         /* read sparsity pattern */
+         hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int));
+         if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix,
+            hbm->rhsind)) goto fail;
+         /* read values */
+         hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double));
+         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix,
+            hbm->rhsval)) goto fail;
+      }
+      else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E')
+      {  /* elemental format */
+         hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double));
+         if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl,
+            hbm->rhsval)) goto fail;
+      }
+      else
+      {  xprintf("%s:%d: right-hand side type `%c' not recognised\n",
+            dsa->fname, dsa->seqn, hbm->rhstyp[0]);
+         goto fail;
+      }
+      /* read starting guesses */
+      if (hbm->rhstyp[1] == 'G')
+      {  hbm->nguess = hbm->nrow * hbm->nrhs;
+         hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double));
+         if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess,
+            hbm->sguess)) goto fail;
+      }
+      /* read solution vectors */
+      if (hbm->rhstyp[2] == 'X')
+      {  hbm->nexact = hbm->nrow * hbm->nrhs;
+         hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double));
+         if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact,
+            hbm->xexact)) goto fail;
+      }
+done: /* reading has been completed */
+      xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn);
+      fclose(dsa->fp);
+      return hbm;
+fail: /* something wrong in Danish kingdom */
+      if (hbm != NULL)
+      {  if (hbm->colptr != NULL) xfree(hbm->colptr);
+         if (hbm->rowind != NULL) xfree(hbm->rowind);
+         if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
+         if (hbm->rhsind != NULL) xfree(hbm->rhsind);
+         if (hbm->values != NULL) xfree(hbm->values);
+         if (hbm->rhsval != NULL) xfree(hbm->rhsval);
+         if (hbm->sguess != NULL) xfree(hbm->sguess);
+         if (hbm->xexact != NULL) xfree(hbm->xexact);
+         xfree(hbm);
+      }
+      if (dsa->fp != NULL) fclose(dsa->fp);
+      return NULL;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  hbm_free_mat - free sparse matrix in Harwell-Boeing format
+*
+*  SYNOPSIS
+*
+*  #include "glphbm.h"
+*  void hbm_free_mat(HBM *hbm);
+*
+*  DESCRIPTION
+*
+*  The hbm_free_mat routine frees all the memory allocated to the data
+*  structure containing a sparse matrix in the Harwell-Boeing format. */
+
+void hbm_free_mat(HBM *hbm)
+{     if (hbm->colptr != NULL) xfree(hbm->colptr);
+      if (hbm->rowind != NULL) xfree(hbm->rowind);
+      if (hbm->rhsptr != NULL) xfree(hbm->rhsptr);
+      if (hbm->rhsind != NULL) xfree(hbm->rhsind);
+      if (hbm->values != NULL) xfree(hbm->values);
+      if (hbm->rhsval != NULL) xfree(hbm->rhsval);
+      if (hbm->sguess != NULL) xfree(hbm->sguess);
+      if (hbm->xexact != NULL) xfree(hbm->xexact);
+      xfree(hbm);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glphbm.h
===================================================================
--- deps/glpk/src/glphbm.h	(revision 9)
+++ deps/glpk/src/glphbm.h	(revision 9)
@@ -0,0 +1,127 @@
+/* glphbm.h (Harwell-Boeing sparse matrix format) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPHBM_H
+#define GLPHBM_H
+
+typedef struct HBM HBM;
+
+struct HBM
+{     /* sparse matrix in Harwell-Boeing format; for details see the
+         report: I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the
+         Harwell-Boeing Sparse Matrix Collection (Release I), 1992 */
+      char title[72+1];
+      /* matrix title (informative) */
+      char key[8+1];
+      /* matrix key (informative) */
+      char mxtype[3+1];
+      /* matrix type:
+         R.. real matrix
+         C.. complex matrix
+         P.. pattern only (no numerical values supplied)
+         .S. symmetric (lower triangle + main diagonal)
+         .U. unsymmetric
+         .H. hermitian (lower triangle + main diagonal)
+         .Z. skew symmetric (lower triangle only)
+         .R. rectangular
+         ..A assembled
+         ..E elemental (unassembled) */
+      char rhstyp[3+1];
+      /* optional types:
+         F.. right-hand sides in dense format
+         M.. right-hand sides in same format as matrix
+         .G. starting vector(s) (guess) is supplied
+         ..X exact solution vector(s) is supplied */
+      char ptrfmt[16+1];
+      /* format for pointers */
+      char indfmt[16+1];
+      /* format for row (or variable) indices */
+      char valfmt[20+1];
+      /* format for numerical values of coefficient matrix */
+      char rhsfmt[20+1];
+      /* format for numerical values of right-hand sides */
+      int totcrd;
+      /* total number of cards excluding header */
+      int ptrcrd;
+      /* number of cards for ponters */
+      int indcrd;
+      /* number of cards for row (or variable) indices */
+      int valcrd;
+      /* number of cards for numerical values */
+      int rhscrd;
+      /* number of lines for right-hand sides;
+         including starting guesses and solution vectors if present;
+         zero indicates no right-hand side data is present */
+      int nrow;
+      /* number of rows (or variables) */
+      int ncol;
+      /* number of columns (or elements) */
+      int nnzero;
+      /* number of row (or variable) indices;
+         equal to number of entries for assembled matrix */
+      int neltvl;
+      /* number of elemental matrix entries;
+         zero in case of assembled matrix */
+      int nrhs;
+      /* number of right-hand sides */
+      int nrhsix;
+      /* number of row indices;
+         ignored in case of unassembled matrix */
+      int nrhsvl;
+      /* total number of entries in all right-hand sides */
+      int nguess;
+      /* total number of entries in all starting guesses */
+      int nexact;
+      /* total number of entries in all solution vectors */
+      int *colptr; /* alias: eltptr */
+      /* column pointers (in case of assembled matrix);
+         elemental matrix pointers (in case of unassembled matrix) */
+      int *rowind; /* alias: varind */
+      /* row indices (in case of assembled matrix);
+         variable indices (in case of unassembled matrix) */
+      int *rhsptr;
+      /* right-hand side pointers */
+      int *rhsind;
+      /* right-hand side indices */
+      double *values;
+      /* matrix values */
+      double *rhsval;
+      /* right-hand side values */
+      double *sguess;
+      /* starting guess values */
+      double *xexact;
+      /* solution vector values */
+};
+
+#define hbm_read_mat _glp_hbm_read_mat
+HBM *hbm_read_mat(const char *fname);
+/* read sparse matrix in Harwell-Boeing format */
+
+#define hbm_free_mat _glp_hbm_free_mat
+void hbm_free_mat(HBM *hbm);
+/* free sparse matrix in Harwell-Boeing format */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpini01.c
===================================================================
--- deps/glpk/src/glpini01.c	(revision 9)
+++ deps/glpk/src/glpini01.c	(revision 9)
@@ -0,0 +1,577 @@
+/* glpini01.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/*----------------------------------------------------------------------
+-- triang - find maximal triangular part of a rectangular matrix.
+--
+-- *Synopsis*
+--
+-- int triang(int m, int n,
+--    void *info, int (*mat)(void *info, int k, int ndx[]),
+--    int rn[], int cn[]);
+--
+-- *Description*
+--
+-- For a given rectangular (sparse) matrix A with m rows and n columns
+-- the routine triang tries to find such permutation matrices P and Q
+-- that the first rows and columns of the matrix B = P*A*Q form a lower
+-- triangular submatrix of as greatest size as possible:
+--
+--                   1                       n
+--                1  * . . . . . . x x x x x x
+--                   * * . . . . . x x x x x x
+--                   * * * . . . . x x x x x x
+--                   * * * * . . . x x x x x x
+--    B = P*A*Q =    * * * * * . . x x x x x x
+--                   * * * * * * . x x x x x x
+--                   * * * * * * * x x x x x x
+--                   x x x x x x x x x x x x x
+--                   x x x x x x x x x x x x x
+--                m  x x x x x x x x x x x x x
+--
+-- where: '*' - elements of the lower triangular part, '.' - structural
+-- zeros, 'x' - other (either non-zero or zero) elements.
+--
+-- The parameter info is a transit pointer passed to the formal routine
+-- mat (see below).
+--
+-- The formal routine mat specifies the given matrix A in both row- and
+-- column-wise formats. In order to obtain an i-th row of the matrix A
+-- the routine triang calls the routine mat with the parameter k = +i,
+-- 1 <= i <= m. In response the routine mat should store column indices
+-- of (non-zero) elements of the i-th row to the locations ndx[1], ...,
+-- ndx[len], where len is number of non-zeros in the i-th row returned
+-- on exit. Analogously, in order to obtain a j-th column of the matrix
+-- A, the routine mat is called with the parameter k = -j, 1 <= j <= n,
+-- and should return pattern of the j-th column in the same way as for
+-- row patterns. Note that the routine mat may be called more than once
+-- for the same rows and columns.
+--
+-- On exit the routine computes two resultant arrays rn and cn, which
+-- define the permutation matrices P and Q, respectively. The array rn
+-- should have at least 1+m locations, where rn[i] = i' (1 <= i <= m)
+-- means that i-th row of the original matrix A corresponds to i'-th row
+-- of the matrix B = P*A*Q. Similarly, the array cn should have at least
+-- 1+n locations, where cn[j] = j' (1 <= j <= n) means that j-th column
+-- of the matrix A corresponds to j'-th column of the matrix B.
+--
+-- *Returns*
+--
+-- The routine triang returns the size of the lower tringular part of
+-- the matrix B = P*A*Q (see the figure above).
+--
+-- *Complexity*
+--
+-- The time complexity of the routine triang is O(nnz), where nnz is
+-- number of non-zeros in the given matrix A.
+--
+-- *Algorithm*
+--
+-- The routine triang starts from the matrix B = P*Q*A, where P and Q
+-- are unity matrices, so initially B = A.
+--
+-- Before the next iteration B = (B1 | B2 | B3), where B1 is partially
+-- built a lower triangular submatrix, B2 is the active submatrix, and
+-- B3 is a submatrix that contains rejected columns. Thus, the current
+-- matrix B looks like follows (initially k1 = 1 and k2 = n):
+--
+--       1         k1         k2         n
+--    1  x . . . . . . . . . . . . . # # #
+--       x x . . . . . . . . . . . . # # #
+--       x x x . . . . . . . . . . # # # #
+--       x x x x . . . . . . . . . # # # #
+--       x x x x x . . . . . . . # # # # #
+--    k1 x x x x x * * * * * * * # # # # #
+--       x x x x x * * * * * * * # # # # #
+--       x x x x x * * * * * * * # # # # #
+--       x x x x x * * * * * * * # # # # #
+--    m  x x x x x * * * * * * * # # # # #
+--       <--B1---> <----B2-----> <---B3-->
+--
+-- On each iteartion the routine looks for a singleton row, i.e. some
+-- row that has the only non-zero in the active submatrix B2. If such
+-- row exists and the corresponding non-zero is b[i,j], where (by the
+-- definition) k1 <= i <= m and k1 <= j <= k2, the routine permutes
+-- k1-th and i-th rows and k1-th and j-th columns of the matrix B (in
+-- order to place the element in the position b[k1,k1]), removes the
+-- k1-th column from the active submatrix B2, and adds this column to
+-- the submatrix B1. If no row singletons exist, but B2 is not empty
+-- yet, the routine chooses a j-th column, which has maximal number of
+-- non-zeros among other columns of B2, removes this column from B2 and
+-- adds it to the submatrix B3 in the hope that new row singletons will
+-- appear in the active submatrix. */
+
+static int triang(int m, int n,
+      void *info, int (*mat)(void *info, int k, int ndx[]),
+      int rn[], int cn[])
+{     int *ndx; /* int ndx[1+max(m,n)]; */
+      /* this array is used for querying row and column patterns of the
+         given matrix A (the third parameter to the routine mat) */
+      int *rs_len; /* int rs_len[1+m]; */
+      /* rs_len[0] is not used;
+         rs_len[i], 1 <= i <= m, is number of non-zeros in the i-th row
+         of the matrix A, which (non-zeros) belong to the current active
+         submatrix */
+      int *rs_head; /* int rs_head[1+n]; */
+      /* rs_head[len], 0 <= len <= n, is the number i of the first row
+         of the matrix A, for which rs_len[i] = len */
+      int *rs_prev; /* int rs_prev[1+m]; */
+      /* rs_prev[0] is not used;
+         rs_prev[i], 1 <= i <= m, is a number i' of the previous row of
+         the matrix A, for which rs_len[i] = rs_len[i'] (zero marks the
+         end of this linked list) */
+      int *rs_next; /* int rs_next[1+m]; */
+      /* rs_next[0] is not used;
+         rs_next[i], 1 <= i <= m, is a number i' of the next row of the
+         matrix A, for which rs_len[i] = rs_len[i'] (zero marks the end
+         this linked list) */
+      int cs_head;
+      /* is a number j of the first column of the matrix A, which has
+         maximal number of non-zeros among other columns */
+      int *cs_prev; /* cs_prev[1+n]; */
+      /* cs_prev[0] is not used;
+         cs_prev[j], 1 <= j <= n, is a number of the previous column of
+         the matrix A with the same or greater number of non-zeros than
+         in the j-th column (zero marks the end of this linked list) */
+      int *cs_next; /* cs_next[1+n]; */
+      /* cs_next[0] is not used;
+         cs_next[j], 1 <= j <= n, is a number of the next column of
+         the matrix A with the same or lesser number of non-zeros than
+         in the j-th column (zero marks the end of this linked list) */
+      int i, j, ii, jj, k1, k2, len, t, size = 0;
+      int *head, *rn_inv, *cn_inv;
+      if (!(m > 0 && n > 0))
+         xerror("triang: m = %d; n = %d; invalid dimension\n", m, n);
+      /* allocate working arrays */
+      ndx = xcalloc(1+(m >= n ? m : n), sizeof(int));
+      rs_len = xcalloc(1+m, sizeof(int));
+      rs_head = xcalloc(1+n, sizeof(int));
+      rs_prev = xcalloc(1+m, sizeof(int));
+      rs_next = xcalloc(1+m, sizeof(int));
+      cs_prev = xcalloc(1+n, sizeof(int));
+      cs_next = xcalloc(1+n, sizeof(int));
+      /* build linked lists of columns of the matrix A with the same
+         number of non-zeros */
+      head = rs_len; /* currently rs_len is used as working array */
+      for (len = 0; len <= m; len ++) head[len] = 0;
+      for (j = 1; j <= n; j++)
+      {  /* obtain length of the j-th column */
+         len = mat(info, -j, ndx);
+         xassert(0 <= len && len <= m);
+         /* include the j-th column in the corresponding linked list */
+         cs_prev[j] = head[len];
+         head[len] = j;
+      }
+      /* merge all linked lists of columns in one linked list, where
+         columns are ordered by descending of their lengths */
+      cs_head = 0;
+      for (len = 0; len <= m; len++)
+      {  for (j = head[len]; j != 0; j = cs_prev[j])
+         {  cs_next[j] = cs_head;
+            cs_head = j;
+         }
+      }
+      jj = 0;
+      for (j = cs_head; j != 0; j = cs_next[j])
+      {  cs_prev[j] = jj;
+         jj = j;
+      }
+      /* build initial doubly linked lists of rows of the matrix A with
+         the same number of non-zeros */
+      for (len = 0; len <= n; len++) rs_head[len] = 0;
+      for (i = 1; i <= m; i++)
+      {  /* obtain length of the i-th row */
+         rs_len[i] = len = mat(info, +i, ndx);
+         xassert(0 <= len && len <= n);
+         /* include the i-th row in the correspondng linked list */
+         rs_prev[i] = 0;
+         rs_next[i] = rs_head[len];
+         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+         rs_head[len] = i;
+      }
+      /* initially all rows and columns of the matrix A are active */
+      for (i = 1; i <= m; i++) rn[i] = 0;
+      for (j = 1; j <= n; j++) cn[j] = 0;
+      /* set initial bounds of the active submatrix */
+      k1 = 1, k2 = n;
+      /* main loop starts here */
+      while (k1 <= k2)
+      {  i = rs_head[1];
+         if (i != 0)
+         {  /* the i-th row of the matrix A is a row singleton, since
+               it has the only non-zero in the active submatrix */
+            xassert(rs_len[i] == 1);
+            /* determine the number j of an active column of the matrix
+               A, in which this non-zero is placed */
+            j = 0;
+            t = mat(info, +i, ndx);
+            xassert(0 <= t && t <= n);
+            for (t = t; t >= 1; t--)
+            {  jj = ndx[t];
+               xassert(1 <= jj && jj <= n);
+               if (cn[jj] == 0)
+               {  xassert(j == 0);
+                  j = jj;
+               }
+            }
+            xassert(j != 0);
+            /* the singleton is a[i,j]; move a[i,j] to the position
+               b[k1,k1] of the matrix B */
+            rn[i] = cn[j] = k1;
+            /* shift the left bound of the active submatrix */
+            k1++;
+            /* increase the size of the lower triangular part */
+            size++;
+         }
+         else
+         {  /* the current active submatrix has no row singletons */
+            /* remove an active column with maximal number of non-zeros
+               from the active submatrix */
+            j = cs_head;
+            xassert(j != 0);
+            cn[j] = k2;
+            /* shift the right bound of the active submatrix */
+            k2--;
+         }
+         /* the j-th column of the matrix A has been removed from the
+            active submatrix */
+         /* remove the j-th column from the linked list */
+         if (cs_prev[j] == 0)
+            cs_head = cs_next[j];
+         else
+            cs_next[cs_prev[j]] = cs_next[j];
+         if (cs_next[j] == 0)
+            /* nop */;
+         else
+            cs_prev[cs_next[j]] = cs_prev[j];
+         /* go through non-zeros of the j-th columns and update active
+            lengths of the corresponding rows */
+         t = mat(info, -j, ndx);
+         xassert(0 <= t && t <= m);
+         for (t = t; t >= 1; t--)
+         {  i = ndx[t];
+            xassert(1 <= i && i <= m);
+            /* the non-zero a[i,j] has left the active submatrix */
+            len = rs_len[i];
+            xassert(len >= 1);
+            /* remove the i-th row from the linked list of rows with
+               active length len */
+            if (rs_prev[i] == 0)
+               rs_head[len] = rs_next[i];
+            else
+               rs_next[rs_prev[i]] = rs_next[i];
+            if (rs_next[i] == 0)
+               /* nop */;
+            else
+               rs_prev[rs_next[i]] = rs_prev[i];
+            /* decrease the active length of the i-th row */
+            rs_len[i] = --len;
+            /* return the i-th row to the corresponding linked list */
+            rs_prev[i] = 0;
+            rs_next[i] = rs_head[len];
+            if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+            rs_head[len] = i;
+         }
+      }
+      /* other rows of the matrix A, which are still active, correspond
+         to rows k1, ..., m of the matrix B (in arbitrary order) */
+      for (i = 1; i <= m; i++) if (rn[i] == 0) rn[i] = k1++;
+      /* but for columns this is not needed, because now the submatrix
+         B2 has no columns */
+      for (j = 1; j <= n; j++) xassert(cn[j] != 0);
+      /* perform some optional checks */
+      /* make sure that rn is a permutation of {1, ..., m} and cn is a
+         permutation of {1, ..., n} */
+      rn_inv = rs_len; /* used as working array */
+      for (ii = 1; ii <= m; ii++) rn_inv[ii] = 0;
+      for (i = 1; i <= m; i++)
+      {  ii = rn[i];
+         xassert(1 <= ii && ii <= m);
+         xassert(rn_inv[ii] == 0);
+         rn_inv[ii] = i;
+      }
+      cn_inv = rs_head; /* used as working array */
+      for (jj = 1; jj <= n; jj++) cn_inv[jj] = 0;
+      for (j = 1; j <= n; j++)
+      {  jj = cn[j];
+         xassert(1 <= jj && jj <= n);
+         xassert(cn_inv[jj] == 0);
+         cn_inv[jj] = j;
+      }
+      /* make sure that the matrix B = P*A*Q really has the form, which
+         was declared */
+      for (ii = 1; ii <= size; ii++)
+      {  int diag = 0;
+         i = rn_inv[ii];
+         t = mat(info, +i, ndx);
+         xassert(0 <= t && t <= n);
+         for (t = t; t >= 1; t--)
+         {  j = ndx[t];
+            xassert(1 <= j && j <= n);
+            jj = cn[j];
+            if (jj <= size) xassert(jj <= ii);
+            if (jj == ii)
+            {  xassert(!diag);
+               diag = 1;
+            }
+         }
+         xassert(diag);
+      }
+      /* free working arrays */
+      xfree(ndx);
+      xfree(rs_len);
+      xfree(rs_head);
+      xfree(rs_prev);
+      xfree(rs_next);
+      xfree(cs_prev);
+      xfree(cs_next);
+      /* return to the calling program */
+      return size;
+}
+
+/*----------------------------------------------------------------------
+-- adv_basis - construct advanced initial LP basis.
+--
+-- *Synopsis*
+--
+-- #include "glpini.h"
+-- void adv_basis(glp_prob *lp);
+--
+-- *Description*
+--
+-- The routine adv_basis constructs an advanced initial basis for an LP
+-- problem object, which the parameter lp points to.
+--
+-- In order to build the initial basis the routine does the following:
+--
+-- 1) includes in the basis all non-fixed auxiliary variables;
+--
+-- 2) includes in the basis as many as possible non-fixed structural
+--    variables preserving triangular form of the basis matrix;
+--
+-- 3) includes in the basis appropriate (fixed) auxiliary variables
+--    in order to complete the basis.
+--
+-- As a result the initial basis has minimum of fixed variables and the
+-- corresponding basis matrix is triangular. */
+
+static int mat(void *info, int k, int ndx[])
+{     /* this auxiliary routine returns the pattern of a given row or
+         a given column of the augmented constraint matrix A~ = (I|-A),
+         in which columns of fixed variables are implicitly cleared */
+      LPX *lp = info;
+      int m = lpx_get_num_rows(lp);
+      int n = lpx_get_num_cols(lp);
+      int typx, i, j, lll, len = 0;
+      if (k > 0)
+      {  /* the pattern of the i-th row is required */
+         i = +k;
+         xassert(1 <= i && i <= m);
+#if 0 /* 22/XII-2003 */
+         /* if the auxiliary variable x[i] is non-fixed, include its
+            element (placed in the i-th column) in the pattern */
+         lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
+         if (typx != LPX_FX) ndx[++len] = i;
+         /* include in the pattern elements placed in columns, which
+            correspond to non-fixed structural varables */
+         i_beg = aa_ptr[i];
+         i_end = i_beg + aa_len[i] - 1;
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         {  j = m + sv_ndx[i_ptr];
+            lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
+            if (typx != LPX_FX) ndx[++len] = j;
+         }
+#else
+         lll = lpx_get_mat_row(lp, i, ndx, NULL);
+         for (k = 1; k <= lll; k++)
+         {  lpx_get_col_bnds(lp, ndx[k], &typx, NULL, NULL);
+            if (typx != LPX_FX) ndx[++len] = m + ndx[k];
+         }
+         lpx_get_row_bnds(lp, i, &typx, NULL, NULL);
+         if (typx != LPX_FX) ndx[++len] = i;
+#endif
+      }
+      else
+      {  /* the pattern of the j-th column is required */
+         j = -k;
+         xassert(1 <= j && j <= m+n);
+         /* if the (auxiliary or structural) variable x[j] is fixed,
+            the pattern of its column is empty */
+         if (j <= m)
+            lpx_get_row_bnds(lp, j, &typx, NULL, NULL);
+         else
+            lpx_get_col_bnds(lp, j-m, &typx, NULL, NULL);
+         if (typx != LPX_FX)
+         {  if (j <= m)
+            {  /* x[j] is non-fixed auxiliary variable */
+               ndx[++len] = j;
+            }
+            else
+            {  /* x[j] is non-fixed structural variables */
+#if 0 /* 22/XII-2003 */
+               j_beg = aa_ptr[j];
+               j_end = j_beg + aa_len[j] - 1;
+               for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+                  ndx[++len] = sv_ndx[j_ptr];
+#else
+               len = lpx_get_mat_col(lp, j-m, ndx, NULL);
+#endif
+            }
+         }
+      }
+      /* return the length of the row/column pattern */
+      return len;
+}
+
+static void adv_basis(glp_prob *lp)
+{     int m = lpx_get_num_rows(lp);
+      int n = lpx_get_num_cols(lp);
+      int i, j, jj, k, size;
+      int *rn, *cn, *rn_inv, *cn_inv;
+      int typx, *tagx = xcalloc(1+m+n, sizeof(int));
+      double lb, ub;
+      xprintf("Constructing initial basis...\n");
+#if 0 /* 13/V-2009 */
+      if (m == 0)
+         xerror("glp_adv_basis: problem has no rows\n");
+      if (n == 0)
+         xerror("glp_adv_basis: problem has no columns\n");
+#else
+      if (m == 0 || n == 0)
+      {  glp_std_basis(lp);
+         return;
+      }
+#endif
+      /* use the routine triang (see above) to find maximal triangular
+         part of the augmented constraint matrix A~ = (I|-A); in order
+         to prevent columns of fixed variables to be included in the
+         triangular part, such columns are implictly removed from the
+         matrix A~ by the routine adv_mat */
+      rn = xcalloc(1+m, sizeof(int));
+      cn = xcalloc(1+m+n, sizeof(int));
+      size = triang(m, m+n, lp, mat, rn, cn);
+      if (lpx_get_int_parm(lp, LPX_K_MSGLEV) >= 3)
+         xprintf("Size of triangular part = %d\n", size);
+      /* the first size rows and columns of the matrix P*A~*Q (where
+         P and Q are permutation matrices defined by the arrays rn and
+         cn) form a lower triangular matrix; build the arrays (rn_inv
+         and cn_inv), which define the matrices inv(P) and inv(Q) */
+      rn_inv = xcalloc(1+m, sizeof(int));
+      cn_inv = xcalloc(1+m+n, sizeof(int));
+      for (i = 1; i <= m; i++) rn_inv[rn[i]] = i;
+      for (j = 1; j <= m+n; j++) cn_inv[cn[j]] = j;
+      /* include the columns of the matrix A~, which correspond to the
+         first size columns of the matrix P*A~*Q, in the basis */
+      for (k = 1; k <= m+n; k++) tagx[k] = -1;
+      for (jj = 1; jj <= size; jj++)
+      {  j = cn_inv[jj];
+         /* the j-th column of A~ is the jj-th column of P*A~*Q */
+         tagx[j] = LPX_BS;
+      }
+      /* if size < m, we need to add appropriate columns of auxiliary
+         variables to the basis */
+      for (jj = size + 1; jj <= m; jj++)
+      {  /* the jj-th column of P*A~*Q should be replaced by the column
+            of the auxiliary variable, for which the only unity element
+            is placed in the position [jj,jj] */
+         i = rn_inv[jj];
+         /* the jj-th row of P*A~*Q is the i-th row of A~, but in the
+            i-th row of A~ the unity element belongs to the i-th column
+            of A~; therefore the disired column corresponds to the i-th
+            auxiliary variable (note that this column doesn't belong to
+            the triangular part found by the routine triang) */
+         xassert(1 <= i && i <= m);
+         xassert(cn[i] > size);
+         tagx[i] = LPX_BS;
+      }
+      /* free working arrays */
+      xfree(rn);
+      xfree(cn);
+      xfree(rn_inv);
+      xfree(cn_inv);
+      /* build tags of non-basic variables */
+      for (k = 1; k <= m+n; k++)
+      {  if (tagx[k] != LPX_BS)
+         {  if (k <= m)
+               lpx_get_row_bnds(lp, k, &typx, &lb, &ub);
+            else
+               lpx_get_col_bnds(lp, k-m, &typx, &lb, &ub);
+            switch (typx)
+            {  case LPX_FR:
+                  tagx[k] = LPX_NF; break;
+               case LPX_LO:
+                  tagx[k] = LPX_NL; break;
+               case LPX_UP:
+                  tagx[k] = LPX_NU; break;
+               case LPX_DB:
+                  tagx[k] =
+                     (fabs(lb) <= fabs(ub) ? LPX_NL : LPX_NU);
+                  break;
+               case LPX_FX:
+                  tagx[k] = LPX_NS; break;
+               default:
+                  xassert(typx != typx);
+            }
+         }
+      }
+      for (k = 1; k <= m+n; k++)
+      {  if (k <= m)
+            lpx_set_row_stat(lp, k, tagx[k]);
+         else
+            lpx_set_col_stat(lp, k-m, tagx[k]);
+      }
+      xfree(tagx);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_adv_basis - construct advanced initial LP basis
+*
+*  SYNOPSIS
+*
+*  void glp_adv_basis(glp_prob *lp, int flags);
+*
+*  DESCRIPTION
+*
+*  The routine glp_adv_basis constructs an advanced initial basis for
+*  the specified problem object.
+*
+*  The parameter flags is reserved for use in the future and must be
+*  specified as zero. */
+
+void glp_adv_basis(glp_prob *lp, int flags)
+{     if (flags != 0)
+         xerror("glp_adv_basis: flags = %d; invalid flags\n", flags);
+      if (lp->m == 0 || lp->n == 0)
+         glp_std_basis(lp);
+      else
+         adv_basis(lp);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpini02.c
===================================================================
--- deps/glpk/src/glpini02.c	(revision 9)
+++ deps/glpk/src/glpini02.c	(revision 9)
@@ -0,0 +1,269 @@
+/* glpini02.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+struct var
+{     /* structural variable */
+      int j;
+      /* ordinal number */
+      double q;
+      /* penalty value */
+};
+
+static int fcmp(const void *ptr1, const void *ptr2)
+{     /* this routine is passed to the qsort() function */
+      struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2;
+      if (col1->q < col2->q) return -1;
+      if (col1->q > col2->q) return +1;
+      return 0;
+}
+
+static int get_column(glp_prob *lp, int j, int ind[], double val[])
+{     /* Bixby's algorithm assumes that the constraint matrix is scaled
+         such that the maximum absolute value in every non-zero row and
+         column is 1 */
+      int k, len;
+      double big;
+      len = glp_get_mat_col(lp, j, ind, val);
+      big = 0.0;
+      for (k = 1; k <= len; k++)
+         if (big < fabs(val[k])) big = fabs(val[k]);
+      if (big == 0.0) big = 1.0;
+      for (k = 1; k <= len; k++) val[k] /= big;
+      return len;
+}
+
+static void cpx_basis(glp_prob *lp)
+{     /* main routine */
+      struct var *C, *C2, *C3, *C4;
+      int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r,
+         *ind;
+      double alpha, gamma, cmax, temp, *v, *val;
+      xprintf("Constructing initial basis...\n");
+      /* determine the number of rows and columns */
+      m = glp_get_num_rows(lp);
+      n = glp_get_num_cols(lp);
+      /* allocate working arrays */
+      C = xcalloc(1+n, sizeof(struct var));
+      I = xcalloc(1+m, sizeof(int));
+      r = xcalloc(1+m, sizeof(int));
+      v = xcalloc(1+m, sizeof(double));
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      /* make all auxiliary variables non-basic */
+      for (i = 1; i <= m; i++)
+      {  if (glp_get_row_type(lp, i) != GLP_DB)
+            glp_set_row_stat(lp, i, GLP_NS);
+         else if (fabs(glp_get_row_lb(lp, i)) <=
+                  fabs(glp_get_row_ub(lp, i)))
+            glp_set_row_stat(lp, i, GLP_NL);
+         else
+            glp_set_row_stat(lp, i, GLP_NU);
+      }
+      /* make all structural variables non-basic */
+      for (j = 1; j <= n; j++)
+      {  if (glp_get_col_type(lp, j) != GLP_DB)
+            glp_set_col_stat(lp, j, GLP_NS);
+         else if (fabs(glp_get_col_lb(lp, j)) <=
+                  fabs(glp_get_col_ub(lp, j)))
+            glp_set_col_stat(lp, j, GLP_NL);
+         else
+            glp_set_col_stat(lp, j, GLP_NU);
+      }
+      /* C2 is a set of free structural variables */
+      n2 = 0, C2 = C + 0;
+      for (j = 1; j <= n; j++)
+      {  type = glp_get_col_type(lp, j);
+         if (type == GLP_FR)
+         {  n2++;
+            C2[n2].j = j;
+            C2[n2].q = 0.0;
+         }
+      }
+      /* C3 is a set of structural variables having excatly one (lower
+         or upper) bound */
+      n3 = 0, C3 = C2 + n2;
+      for (j = 1; j <= n; j++)
+      {  type = glp_get_col_type(lp, j);
+         if (type == GLP_LO)
+         {  n3++;
+            C3[n3].j = j;
+            C3[n3].q = + glp_get_col_lb(lp, j);
+         }
+         else if (type == GLP_UP)
+         {  n3++;
+            C3[n3].j = j;
+            C3[n3].q = - glp_get_col_ub(lp, j);
+         }
+      }
+      /* C4 is a set of structural variables having both (lower and
+         upper) bounds */
+      n4 = 0, C4 = C3 + n3;
+      for (j = 1; j <= n; j++)
+      {  type = glp_get_col_type(lp, j);
+         if (type == GLP_DB)
+         {  n4++;
+            C4[n4].j = j;
+            C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j);
+         }
+      }
+      /* compute gamma = max{|c[j]|: 1 <= j <= n} */
+      gamma = 0.0;
+      for (j = 1; j <= n; j++)
+      {  temp = fabs(glp_get_obj_coef(lp, j));
+         if (gamma < temp) gamma = temp;
+      }
+      /* compute cmax */
+      cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma);
+      /* compute final penalty for all structural variables within sets
+         C2, C3, and C4 */
+      switch (glp_get_obj_dir(lp))
+      {  case GLP_MIN: temp = +1.0; break;
+         case GLP_MAX: temp = -1.0; break;
+         default: xassert(lp != lp);
+      }
+      for (k = 1; k <= n2+n3+n4; k++)
+      {  j = C[k].j;
+         C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax;
+      }
+      /* sort structural variables within C2, C3, and C4 in ascending
+         order of penalty value */
+      qsort(C2+1, n2, sizeof(struct var), fcmp);
+      for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q);
+      qsort(C3+1, n3, sizeof(struct var), fcmp);
+      for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q);
+      qsort(C4+1, n4, sizeof(struct var), fcmp);
+      for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q);
+      /*** STEP 1 ***/
+      for (i = 1; i <= m; i++)
+      {  type = glp_get_row_type(lp, i);
+         if (type != GLP_FX)
+         {  /* row i is either free or inequality constraint */
+            glp_set_row_stat(lp, i, GLP_BS);
+            I[i] = 1;
+            r[i] = 1;
+         }
+         else
+         {  /* row i is equality constraint */
+            I[i] = 0;
+            r[i] = 0;
+         }
+         v[i] = +DBL_MAX;
+      }
+      /*** STEP 2 ***/
+      for (k = 1; k <= n2+n3+n4; k++)
+      {  jk = C[k].j;
+         len = get_column(lp, jk, ind, val);
+         /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such
+            that alpha = |A[l',jk]| */
+         alpha = 0.0, ll = 0;
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (r[l] == 0 && alpha < fabs(val[t]))
+               alpha = fabs(val[t]), ll = l;
+         }
+         if (alpha >= 0.99)
+         {  /* B := B union {jk} */
+            glp_set_col_stat(lp, jk, GLP_BS);
+            I[ll] = 1;
+            v[ll] = alpha;
+            /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
+            for (t = 1; t <= len; t++)
+            {  l = ind[t];
+               if (val[t] != 0.0) r[l]++;
+            }
+            /* continue to the next k */
+            continue;
+         }
+         /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the
+            next k */
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (fabs(val[t]) > 0.01 * v[l]) break;
+         }
+         if (t <= len) continue;
+         /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l'
+            be such that alpha = |A[l',jk]| */
+         alpha = 0.0, ll = 0;
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (I[l] == 0 && alpha < fabs(val[t]))
+               alpha = fabs(val[t]), ll = l;
+         }
+         /* if alpha = 0, continue to the next k */
+         if (alpha == 0.0) continue;
+         /* B := B union {jk} */
+         glp_set_col_stat(lp, jk, GLP_BS);
+         I[ll] = 1;
+         v[ll] = alpha;
+         /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */
+         for (t = 1; t <= len; t++)
+         {  l = ind[t];
+            if (val[t] != 0.0) r[l]++;
+         }
+      }
+      /*** STEP 3 ***/
+      /* add an artificial variable (auxiliary variable for equality
+         constraint) to cover each remaining uncovered row */
+      for (i = 1; i <= m; i++)
+         if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS);
+      /* free working arrays */
+      xfree(C);
+      xfree(I);
+      xfree(r);
+      xfree(v);
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_cpx_basis - construct Bixby's initial LP basis
+*
+*  SYNOPSIS
+*
+*  void glp_cpx_basis(glp_prob *lp);
+*
+*  DESCRIPTION
+*
+*  The routine glp_cpx_basis constructs an advanced initial basis for
+*  the specified problem object.
+*
+*  The routine is based on Bixby's algorithm described in the paper:
+*
+*  Robert E. Bixby. Implementing the Simplex Method: The Initial Basis.
+*  ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */
+
+void glp_cpx_basis(glp_prob *lp)
+{     if (lp->m == 0 || lp->n == 0)
+         glp_std_basis(lp);
+      else
+         cpx_basis(lp);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpios.h
===================================================================
--- deps/glpk/src/glpios.h	(revision 9)
+++ deps/glpk/src/glpios.h	(revision 9)
@@ -0,0 +1,593 @@
+/* glpios.h (integer optimization suite) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPIOS_H
+#define GLPIOS_H
+
+#define GLP_TREE_DEFINED
+typedef struct glp_tree glp_tree;
+
+#include "glpapi.h"
+
+typedef struct IOSLOT IOSLOT;
+typedef struct IOSNPD IOSNPD;
+typedef struct IOSBND IOSBND;
+typedef struct IOSTAT IOSTAT;
+typedef struct IOSROW IOSROW;
+typedef struct IOSAIJ IOSAIJ;
+typedef struct IOSPOOL IOSPOOL;
+typedef struct IOSCUT IOSCUT;
+
+struct glp_tree
+{     /* branch-and-bound tree */
+      int magic;
+      /* magic value used for debugging */
+      DMP *pool;
+      /* memory pool to store all IOS components */
+      int n;
+      /* number of columns (variables) */
+      /*--------------------------------------------------------------*/
+      /* problem components corresponding to the original MIP and its
+         LP relaxation (used to restore the original problem object on
+         exit from the solver) */
+      int orig_m;
+      /* number of rows */
+      unsigned char *orig_type; /* uchar orig_type[1+orig_m+n]; */
+      /* types of all variables */
+      double *orig_lb; /* double orig_lb[1+orig_m+n]; */
+      /* lower bounds of all variables */
+      double *orig_ub; /* double orig_ub[1+orig_m+n]; */
+      /* upper bounds of all variables */
+      unsigned char *orig_stat; /* uchar orig_stat[1+orig_m+n]; */
+      /* statuses of all variables */
+      double *orig_prim; /* double orig_prim[1+orig_m+n]; */
+      /* primal values of all variables */
+      double *orig_dual; /* double orig_dual[1+orig_m+n]; */
+      /* dual values of all variables */
+      double orig_obj;
+      /* optimal objective value for LP relaxation */
+      /*--------------------------------------------------------------*/
+      /* branch-and-bound tree */
+      int nslots;
+      /* length of the array of slots (enlarged automatically) */
+      int avail;
+      /* index of the first free slot; 0 means all slots are in use */
+      IOSLOT *slot; /* IOSLOT slot[1+nslots]; */
+      /* array of slots:
+         slot[0] is not used;
+         slot[p], 1 <= p <= nslots, either contains a pointer to some
+         node of the branch-and-bound tree, in which case p is used on
+         API level as the reference number of corresponding subproblem,
+         or is free; all free slots are linked into single linked list;
+         slot[1] always contains a pointer to the root node (it is free
+         only if the tree is empty) */
+      IOSNPD *head;
+      /* pointer to the head of the active list */
+      IOSNPD *tail;
+      /* pointer to the tail of the active list */
+      /* the active list is a doubly linked list of active subproblems
+         which correspond to leaves of the tree; all subproblems in the
+         active list are ordered chronologically (each a new subproblem
+         is always added to the tail of the list) */
+      int a_cnt;
+      /* current number of active nodes (including the current one) */
+      int n_cnt;
+      /* current number of all (active and inactive) nodes */
+      int t_cnt;
+      /* total number of nodes including those which have been already
+         removed from the tree; this count is increased by one whenever
+         a new node is created and never decreased */
+      /*--------------------------------------------------------------*/
+      /* problem components corresponding to the root subproblem */
+      int root_m;
+      /* number of rows */
+      unsigned char *root_type; /* uchar root_type[1+root_m+n]; */
+      /* types of all variables */
+      double *root_lb; /* double root_lb[1+root_m+n]; */
+      /* lower bounds of all variables */
+      double *root_ub; /* double root_ub[1+root_m+n]; */
+      /* upper bounds of all variables */
+      unsigned char *root_stat; /* uchar root_stat[1+root_m+n]; */
+      /* statuses of all variables */
+      /*--------------------------------------------------------------*/
+      /* current subproblem and its LP relaxation */
+      IOSNPD *curr;
+      /* pointer to the current subproblem (which can be only active);
+         NULL means the current subproblem does not exist */
+      glp_prob *mip;
+      /* original problem object passed to the solver; if the current
+         subproblem exists, its LP segment corresponds to LP relaxation
+         of the current subproblem; if the current subproblem does not
+         exist, its LP segment corresponds to LP relaxation of the root
+         subproblem (note that the root subproblem may differ from the
+         original MIP, because it may be preprocessed and/or may have
+         additional rows) */
+      unsigned char *non_int; /* uchar non_int[1+n]; */
+      /* these column flags are set each time when LP relaxation of the
+         current subproblem has been solved;
+         non_int[0] is not used;
+         non_int[j], 1 <= j <= n, is j-th column flag; if this flag is
+         set, corresponding variable is required to be integer, but its
+         value in basic solution is fractional */
+      /*--------------------------------------------------------------*/
+      /* problem components corresponding to the parent (predecessor)
+         subproblem for the current subproblem; used to inspect changes
+         on freezing the current subproblem */
+      int pred_m;
+      /* number of rows */
+      int pred_max;
+      /* length of the following four arrays (enlarged automatically),
+         pred_max >= pred_m + n */
+      unsigned char *pred_type; /* uchar pred_type[1+pred_m+n]; */
+      /* types of all variables */
+      double *pred_lb; /* double pred_lb[1+pred_m+n]; */
+      /* lower bounds of all variables */
+      double *pred_ub; /* double pred_ub[1+pred_m+n]; */
+      /* upper bounds of all variables */
+      unsigned char *pred_stat; /* uchar pred_stat[1+pred_m+n]; */
+      /* statuses of all variables */
+      /****************************************************************/
+      /* built-in cut generators segment */
+      IOSPOOL *local;
+      /* local cut pool */
+      void *mir_gen;
+      /* pointer to working area used by the MIR cut generator */
+      void *clq_gen;
+      /* pointer to working area used by the clique cut generator */
+      /*--------------------------------------------------------------*/
+      void *pcost;
+      /* pointer to working area used on pseudocost branching */
+      int *iwrk; /* int iwrk[1+n]; */
+      /* working array */
+      double *dwrk; /* double dwrk[1+n]; */
+      /* working array */
+      /*--------------------------------------------------------------*/
+      /* control parameters and statistics */
+      const glp_iocp *parm;
+      /* copy of control parameters passed to the solver */
+      glp_long tm_beg;
+      /* starting time of the search, in seconds; the total time of the
+         search is the difference between xtime() and tm_beg */
+      glp_long tm_lag;
+      /* the most recent time, in seconds, at which the progress of the
+         the search was displayed */
+      int sol_cnt;
+      /* number of integer feasible solutions found */
+      /*--------------------------------------------------------------*/
+      /* advanced solver interface */
+      int reason;
+      /* flag indicating the reason why the callback routine is being
+         called (see glpk.h) */
+      int stop;
+      /* flag indicating that the callback routine requires premature
+         termination of the search */
+      int next_p;
+      /* reference number of active subproblem selected to continue
+         the search; 0 means no subproblem has been selected */
+      int reopt;
+      /* flag indicating that the current LP relaxation needs to be
+         re-optimized */
+      int reinv;
+      /* flag indicating that some (non-active) rows were removed from
+         the current LP relaxation, so if there no new rows appear, the
+         basis must be re-factorized */
+      int br_var;
+      /* the number of variable chosen to branch on */
+      int br_sel;
+      /* flag indicating which branch (subproblem) is suggested to be
+         selected to continue the search:
+         GLP_DN_BRNCH - select down-branch
+         GLP_UP_BRNCH - select up-branch
+         GLP_NO_BRNCH - use general selection technique */
+      int child;
+      /* subproblem reference number corresponding to br_sel */
+};
+
+struct IOSLOT
+{     /* node subproblem slot */
+      IOSNPD *node;
+      /* pointer to subproblem descriptor; NULL means free slot */
+      int next;
+      /* index of another free slot (only if this slot is free) */
+};
+
+struct IOSNPD
+{     /* node subproblem descriptor */
+      int p;
+      /* subproblem reference number (it is the index to corresponding
+         slot, i.e. slot[p] points to this descriptor) */
+      IOSNPD *up;
+      /* pointer to the parent subproblem; NULL means this node is the
+         root of the tree, in which case p = 1 */
+      int level;
+      /* node level (the root node has level 0) */
+      int count;
+      /* if count = 0, this subproblem is active; if count > 0, this
+         subproblem is inactive, in which case count is the number of
+         its child subproblems */
+      /* the following three linked lists are destroyed on reviving and
+         built anew on freezing the subproblem: */
+      IOSBND *b_ptr;
+      /* linked list of rows and columns of the parent subproblem whose
+         types and bounds were changed */
+      IOSTAT *s_ptr;
+      /* linked list of rows and columns of the parent subproblem whose
+         statuses were changed */
+      IOSROW *r_ptr;
+      /* linked list of rows (cuts) added to the parent subproblem */
+      int solved;
+      /* how many times LP relaxation of this subproblem was solved;
+         for inactive subproblem this count is always non-zero;
+         for active subproblem, which is not current, this count may be
+         non-zero, if the subproblem was temporarily suspended */
+      double lp_obj;
+      /* optimal objective value to LP relaxation of this subproblem;
+         on creating a subproblem this value is inherited from its
+         parent; for the root subproblem, which has no parent, this
+         value is initially set to -DBL_MAX (minimization) or +DBL_MAX
+         (maximization); each time the subproblem is re-optimized, this
+         value is appropriately changed */
+      double bound;
+      /* local lower (minimization) or upper (maximization) bound for
+         integer optimal solution to *this* subproblem; this bound is
+         local in the sense that only subproblems in the subtree rooted
+         at this node cannot have better integer feasible solutions;
+         on creating a subproblem its local bound is inherited from its
+         parent and then can be made stronger (never weaker); for the
+         root subproblem its local bound is initially set to -DBL_MAX
+         (minimization) or +DBL_MAX (maximization) and then improved as
+         the root LP relaxation has been solved */
+      /* the following two quantities are defined only if LP relaxation
+         of this subproblem was solved at least once (solved > 0): */
+      int ii_cnt;
+      /* number of integer variables whose value in optimal solution to
+         LP relaxation of this subproblem is fractional */
+      double ii_sum;
+      /* sum of integer infeasibilities */
+#if 1 /* 30/XI-2009 */
+      int changed;
+      /* how many times this subproblem was re-formulated (by adding
+         cutting plane constraints) */
+#endif
+      int br_var;
+      /* ordinal number of branching variable, 1 <= br_var <= n, used
+         to split this subproblem; 0 means that either this subproblem
+         is active or branching was made on a constraint */
+      double br_val;
+      /* (fractional) value of branching variable in optimal solution
+         to final LP relaxation of this subproblem */
+      void *data; /* char data[tree->cb_size]; */
+      /* pointer to the application-specific data */
+      IOSNPD *temp;
+      /* working pointer used by some routines */
+      IOSNPD *prev;
+      /* pointer to previous subproblem in the active list */
+      IOSNPD *next;
+      /* pointer to next subproblem in the active list */
+};
+
+struct IOSBND
+{     /* bounds change entry */
+      int k;
+      /* ordinal number of corresponding row (1 <= k <= m) or column
+         (m+1 <= k <= m+n), where m and n are the number of rows and
+         columns, resp., in the parent subproblem */
+      unsigned char type;
+      /* new type */
+      double lb;
+      /* new lower bound */
+      double ub;
+      /* new upper bound */
+      IOSBND *next;
+      /* pointer to next entry for the same subproblem */
+};
+
+struct IOSTAT
+{     /* status change entry */
+      int k;
+      /* ordinal number of corresponding row (1 <= k <= m) or column
+         (m+1 <= k <= m+n), where m and n are the number of rows and
+         columns, resp., in the parent subproblem */
+      unsigned char stat;
+      /* new status */
+      IOSTAT *next;
+      /* pointer to next entry for the same subproblem */
+};
+
+struct IOSROW
+{     /* row (constraint) addition entry */
+      char *name;
+      /* row name or NULL */
+      unsigned char origin;
+      /* row origin flag (see glp_attr.origin) */
+      unsigned char klass;
+      /* row class descriptor (see glp_attr.klass) */
+      unsigned char type;
+      /* row type (GLP_LO, GLP_UP, etc.) */
+      double lb;
+      /* row lower bound */
+      double ub;
+      /* row upper bound */
+      IOSAIJ *ptr;
+      /* pointer to the row coefficient list */
+      double rii;
+      /* row scale factor */
+      unsigned char stat;
+      /* row status (GLP_BS, GLP_NL, etc.) */
+      IOSROW *next;
+      /* pointer to next entry for the same subproblem */
+};
+
+struct IOSAIJ
+{     /* constraint coefficient */
+      int j;
+      /* variable (column) number, 1 <= j <= n */
+      double val;
+      /* non-zero coefficient value */
+      IOSAIJ *next;
+      /* pointer to next coefficient for the same row */
+};
+
+struct IOSPOOL
+{     /* cut pool */
+      int size;
+      /* pool size = number of cuts in the pool */
+      IOSCUT *head;
+      /* pointer to the first cut */
+      IOSCUT *tail;
+      /* pointer to the last cut */
+      int ord;
+      /* ordinal number of the current cut, 1 <= ord <= size */
+      IOSCUT *curr;
+      /* pointer to the current cut */
+};
+
+struct IOSCUT
+{     /* cut (cutting plane constraint) */
+      char *name;
+      /* cut name or NULL */
+      unsigned char klass;
+      /* cut class descriptor (see glp_attr.klass) */
+      IOSAIJ *ptr;
+      /* pointer to the cut coefficient list */
+      unsigned char type;
+      /* cut type:
+         GLP_LO: sum a[j] * x[j] >= b
+         GLP_UP: sum a[j] * x[j] <= b
+         GLP_FX: sum a[j] * x[j]  = b */
+      double rhs;
+      /* cut right-hand side */
+      IOSCUT *prev;
+      /* pointer to previous cut */
+      IOSCUT *next;
+      /* pointer to next cut */
+};
+
+#define ios_create_tree _glp_ios_create_tree
+glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
+/* create branch-and-bound tree */
+
+#define ios_revive_node _glp_ios_revive_node
+void ios_revive_node(glp_tree *tree, int p);
+/* revive specified subproblem */
+
+#define ios_freeze_node _glp_ios_freeze_node
+void ios_freeze_node(glp_tree *tree);
+/* freeze current subproblem */
+
+#define ios_clone_node _glp_ios_clone_node
+void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
+/* clone specified subproblem */
+
+#define ios_delete_node _glp_ios_delete_node
+void ios_delete_node(glp_tree *tree, int p);
+/* delete specified subproblem */
+
+#define ios_delete_tree _glp_ios_delete_tree
+void ios_delete_tree(glp_tree *tree);
+/* delete branch-and-bound tree */
+
+#define ios_eval_degrad _glp_ios_eval_degrad
+void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
+/* estimate obj. degrad. for down- and up-branches */
+
+#define ios_round_bound _glp_ios_round_bound
+double ios_round_bound(glp_tree *tree, double bound);
+/* improve local bound by rounding */
+
+#define ios_is_hopeful _glp_ios_is_hopeful
+int ios_is_hopeful(glp_tree *tree, double bound);
+/* check if subproblem is hopeful */
+
+#define ios_best_node _glp_ios_best_node
+int ios_best_node(glp_tree *tree);
+/* find active node with best local bound */
+
+#define ios_relative_gap _glp_ios_relative_gap
+double ios_relative_gap(glp_tree *tree);
+/* compute relative mip gap */
+
+#define ios_solve_node _glp_ios_solve_node
+int ios_solve_node(glp_tree *tree);
+/* solve LP relaxation of current subproblem */
+
+#define ios_create_pool _glp_ios_create_pool
+IOSPOOL *ios_create_pool(glp_tree *tree);
+/* create cut pool */
+
+#define ios_add_row _glp_ios_add_row
+int ios_add_row(glp_tree *tree, IOSPOOL *pool,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs);
+/* add row (constraint) to the cut pool */
+
+#define ios_find_row _glp_ios_find_row
+IOSCUT *ios_find_row(IOSPOOL *pool, int i);
+/* find row (constraint) in the cut pool */
+
+#define ios_del_row _glp_ios_del_row
+void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i);
+/* remove row (constraint) from the cut pool */
+
+#define ios_clear_pool _glp_ios_clear_pool
+void ios_clear_pool(glp_tree *tree, IOSPOOL *pool);
+/* remove all rows (constraints) from the cut pool */
+
+#define ios_delete_pool _glp_ios_delete_pool
+void ios_delete_pool(glp_tree *tree, IOSPOOL *pool);
+/* delete cut pool */
+
+#define ios_preprocess_node _glp_ios_preprocess_node
+int ios_preprocess_node(glp_tree *tree, int max_pass);
+/* preprocess current subproblem */
+
+#define ios_driver _glp_ios_driver
+int ios_driver(glp_tree *tree);
+/* branch-and-bound driver */
+
+/**********************************************************************/
+
+typedef struct IOSVEC IOSVEC;
+
+struct IOSVEC
+{     /* sparse vector v = (v[j]) */
+      int n;
+      /* dimension, n >= 0 */
+      int nnz;
+      /* number of non-zero components, 0 <= nnz <= n */
+      int *pos; /* int pos[1+n]; */
+      /* pos[j] = k, 1 <= j <= n, is position of (non-zero) v[j] in the
+         arrays ind and val, where 1 <= k <= nnz; pos[j] = 0 means that
+         v[j] is structural zero */
+      int *ind; /* int ind[1+n]; */
+      /* ind[k] = j, 1 <= k <= nnz, is index of v[j] */
+      double *val; /* double val[1+n]; */
+      /* val[k], 1 <= k <= nnz, is a numeric value of v[j] */
+};
+
+#define ios_create_vec _glp_ios_create_vec
+IOSVEC *ios_create_vec(int n);
+/* create sparse vector */
+
+#define ios_check_vec _glp_ios_check_vec
+void ios_check_vec(IOSVEC *v);
+/* check that sparse vector has correct representation */
+
+#define ios_get_vj _glp_ios_get_vj
+double ios_get_vj(IOSVEC *v, int j);
+/* retrieve component of sparse vector */
+
+#define ios_set_vj _glp_ios_set_vj
+void ios_set_vj(IOSVEC *v, int j, double val);
+/* set/change component of sparse vector */
+
+#define ios_clear_vec _glp_ios_clear_vec
+void ios_clear_vec(IOSVEC *v);
+/* set all components of sparse vector to zero */
+
+#define ios_clean_vec _glp_ios_clean_vec
+void ios_clean_vec(IOSVEC *v, double eps);
+/* remove zero or small components from sparse vector */
+
+#define ios_copy_vec _glp_ios_copy_vec
+void ios_copy_vec(IOSVEC *x, IOSVEC *y);
+/* copy sparse vector (x := y) */
+
+#define ios_linear_comb _glp_ios_linear_comb
+void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
+/* compute linear combination (x := x + a * y) */
+
+#define ios_delete_vec _glp_ios_delete_vec
+void ios_delete_vec(IOSVEC *v);
+/* delete sparse vector */
+
+/**********************************************************************/
+
+#define ios_gmi_gen _glp_ios_gmi_gen
+void ios_gmi_gen(glp_tree *tree);
+/* generate Gomory's mixed integer cuts */
+
+#define ios_mir_init _glp_ios_mir_init
+void *ios_mir_init(glp_tree *tree);
+/* initialize MIR cut generator */
+
+#define ios_mir_gen _glp_ios_mir_gen
+void ios_mir_gen(glp_tree *tree, void *gen);
+/* generate MIR cuts */
+
+#define ios_mir_term _glp_ios_mir_term
+void ios_mir_term(void *gen);
+/* terminate MIR cut generator */
+
+#define ios_cov_gen _glp_ios_cov_gen
+void ios_cov_gen(glp_tree *tree);
+/* generate mixed cover cuts */
+
+#define ios_clq_init _glp_ios_clq_init
+void *ios_clq_init(glp_tree *tree);
+/* initialize clique cut generator */
+
+#define ios_clq_gen _glp_ios_clq_gen
+void ios_clq_gen(glp_tree *tree, void *gen);
+/* generate clique cuts */
+
+#define ios_clq_term _glp_ios_clq_term
+void ios_clq_term(void *gen);
+/* terminate clique cut generator */
+
+#define ios_pcost_init _glp_ios_pcost_init
+void *ios_pcost_init(glp_tree *tree);
+/* initialize working data used on pseudocost branching */
+
+#define ios_pcost_branch _glp_ios_pcost_branch
+int ios_pcost_branch(glp_tree *T, int *next);
+/* choose branching variable with pseudocost branching */
+
+#define ios_pcost_update _glp_ios_pcost_update
+void ios_pcost_update(glp_tree *tree);
+/* update history information for pseudocost branching */
+
+#define ios_pcost_free _glp_ios_pcost_free
+void ios_pcost_free(glp_tree *tree);
+/* free working area used on pseudocost branching */
+
+#define ios_feas_pump _glp_ios_feas_pump
+void ios_feas_pump(glp_tree *T);
+/* feasibility pump heuristic */
+
+#define ios_process_cuts _glp_ios_process_cuts
+void ios_process_cuts(glp_tree *T);
+/* process cuts stored in the local cut pool */
+
+#define ios_choose_node _glp_ios_choose_node
+int ios_choose_node(glp_tree *T);
+/* select subproblem to continue the search */
+
+#define ios_choose_var _glp_ios_choose_var
+int ios_choose_var(glp_tree *T, int *next);
+/* select variable to branch on */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpios01.c
===================================================================
--- deps/glpk/src/glpios01.c	(revision 9)
+++ deps/glpk/src/glpios01.c	(revision 9)
@@ -0,0 +1,1611 @@
+/* glpios01.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_create_tree - create branch-and-bound tree
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine ios_create_tree creates the branch-and-bound tree.
+*
+*  Being created the tree consists of the only root subproblem whose
+*  reference number is 1. Note that initially the root subproblem is in
+*  frozen state and therefore needs to be revived.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the tree created. */
+
+static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent);
+
+glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm)
+{     int m = mip->m;
+      int n = mip->n;
+      glp_tree *tree;
+      int i, j;
+      xassert(mip->tree == NULL);
+      mip->tree = tree = xmalloc(sizeof(glp_tree));
+      tree->pool = dmp_create_pool();
+      tree->n = n;
+      /* save original problem components */
+      tree->orig_m = m;
+      tree->orig_type = xcalloc(1+m+n, sizeof(char));
+      tree->orig_lb = xcalloc(1+m+n, sizeof(double));
+      tree->orig_ub = xcalloc(1+m+n, sizeof(double));
+      tree->orig_stat = xcalloc(1+m+n, sizeof(char));
+      tree->orig_prim = xcalloc(1+m+n, sizeof(double));
+      tree->orig_dual = xcalloc(1+m+n, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = mip->row[i];
+         tree->orig_type[i] = (char)row->type;
+         tree->orig_lb[i] = row->lb;
+         tree->orig_ub[i] = row->ub;
+         tree->orig_stat[i] = (char)row->stat;
+         tree->orig_prim[i] = row->prim;
+         tree->orig_dual[i] = row->dual;
+      }
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         tree->orig_type[m+j] = (char)col->type;
+         tree->orig_lb[m+j] = col->lb;
+         tree->orig_ub[m+j] = col->ub;
+         tree->orig_stat[m+j] = (char)col->stat;
+         tree->orig_prim[m+j] = col->prim;
+         tree->orig_dual[m+j] = col->dual;
+      }
+      tree->orig_obj = mip->obj_val;
+      /* initialize the branch-and-bound tree */
+      tree->nslots = 0;
+      tree->avail = 0;
+      tree->slot = NULL;
+      tree->head = tree->tail = NULL;
+      tree->a_cnt = tree->n_cnt = tree->t_cnt = 0;
+      /* the root subproblem is not solved yet, so its final components
+         are unknown so far */
+      tree->root_m = 0;
+      tree->root_type = NULL;
+      tree->root_lb = tree->root_ub = NULL;
+      tree->root_stat = NULL;
+      /* the current subproblem does not exist yet */
+      tree->curr = NULL;
+      tree->mip = mip;
+      /*tree->solved = 0;*/
+      tree->non_int = xcalloc(1+n, sizeof(char));
+      memset(&tree->non_int[1], 0, n);
+      /* arrays to save parent subproblem components will be allocated
+         later */
+      tree->pred_m = tree->pred_max = 0;
+      tree->pred_type = NULL;
+      tree->pred_lb = tree->pred_ub = NULL;
+      tree->pred_stat = NULL;
+      /* cut generator */
+      tree->local = ios_create_pool(tree);
+      /*tree->first_attempt = 1;*/
+      /*tree->max_added_cuts = 0;*/
+      /*tree->min_eff = 0.0;*/
+      /*tree->miss = 0;*/
+      /*tree->just_selected = 0;*/
+      tree->mir_gen = NULL;
+      tree->clq_gen = NULL;
+      /*tree->round = 0;*/
+#if 0
+      /* create the conflict graph */
+      tree->n_ref = xcalloc(1+n, sizeof(int));
+      memset(&tree->n_ref[1], 0, n * sizeof(int));
+      tree->c_ref = xcalloc(1+n, sizeof(int));
+      memset(&tree->c_ref[1], 0, n * sizeof(int));
+      tree->g = scg_create_graph(0);
+      tree->j_ref = xcalloc(1+tree->g->n_max, sizeof(int));
+#endif
+      /* pseudocost branching */
+      tree->pcost = NULL;
+      tree->iwrk = xcalloc(1+n, sizeof(int));
+      tree->dwrk = xcalloc(1+n, sizeof(double));
+      /* initialize control parameters */
+      tree->parm = parm;
+      tree->tm_beg = xtime();
+      tree->tm_lag = xlset(0);
+      tree->sol_cnt = 0;
+      /* initialize advanced solver interface */
+      tree->reason = 0;
+      tree->reopt = 0;
+      tree->reinv = 0;
+      tree->br_var = 0;
+      tree->br_sel = 0;
+      tree->child = 0;
+      tree->next_p = 0;
+      /*tree->btrack = NULL;*/
+      tree->stop = 0;
+      /* create the root subproblem, which initially is identical to
+         the original MIP */
+      new_node(tree, NULL);
+      return tree;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_revive_node - revive specified subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_revive_node(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine ios_revive_node revives the specified subproblem, whose
+*  reference number is p, and thereby makes it the current subproblem.
+*  Note that the specified subproblem must be active. Besides, if the
+*  current subproblem already exists, it must be frozen before reviving
+*  another subproblem. */
+
+void ios_revive_node(glp_tree *tree, int p)
+{     glp_prob *mip = tree->mip;
+      IOSNPD *node, *root;
+      /* obtain pointer to the specified subproblem */
+      xassert(1 <= p && p <= tree->nslots);
+      node = tree->slot[p].node;
+      xassert(node != NULL);
+      /* the specified subproblem must be active */
+      xassert(node->count == 0);
+      /* the current subproblem must not exist */
+      xassert(tree->curr == NULL);
+      /* the specified subproblem becomes current */
+      tree->curr = node;
+      /*tree->solved = 0;*/
+      /* obtain pointer to the root subproblem */
+      root = tree->slot[1].node;
+      xassert(root != NULL);
+      /* at this point problem object components correspond to the root
+         subproblem, so if the root subproblem should be revived, there
+         is nothing more to do */
+      if (node == root) goto done;
+      xassert(mip->m == tree->root_m);
+      /* build path from the root to the current node */
+      node->temp = NULL;
+      for (node = node; node != NULL; node = node->up)
+      {  if (node->up == NULL)
+            xassert(node == root);
+         else
+            node->up->temp = node;
+      }
+      /* go down from the root to the current node and make necessary
+         changes to restore components of the current subproblem */
+      for (node = root; node != NULL; node = node->temp)
+      {  int m = mip->m;
+         int n = mip->n;
+         /* if the current node is reached, the problem object at this
+            point corresponds to its parent, so save attributes of rows
+            and columns for the parent subproblem */
+         if (node->temp == NULL)
+         {  int i, j;
+            tree->pred_m = m;
+            /* allocate/reallocate arrays, if necessary */
+            if (tree->pred_max < m + n)
+            {  int new_size = m + n + 100;
+               if (tree->pred_type != NULL) xfree(tree->pred_type);
+               if (tree->pred_lb != NULL) xfree(tree->pred_lb);
+               if (tree->pred_ub != NULL) xfree(tree->pred_ub);
+               if (tree->pred_stat != NULL) xfree(tree->pred_stat);
+               tree->pred_max = new_size;
+               tree->pred_type = xcalloc(1+new_size, sizeof(char));
+               tree->pred_lb = xcalloc(1+new_size, sizeof(double));
+               tree->pred_ub = xcalloc(1+new_size, sizeof(double));
+               tree->pred_stat = xcalloc(1+new_size, sizeof(char));
+            }
+            /* save row attributes */
+            for (i = 1; i <= m; i++)
+            {  GLPROW *row = mip->row[i];
+               tree->pred_type[i] = (char)row->type;
+               tree->pred_lb[i] = row->lb;
+               tree->pred_ub[i] = row->ub;
+               tree->pred_stat[i] = (char)row->stat;
+            }
+            /* save column attributes */
+            for (j = 1; j <= n; j++)
+            {  GLPCOL *col = mip->col[j];
+               tree->pred_type[mip->m+j] = (char)col->type;
+               tree->pred_lb[mip->m+j] = col->lb;
+               tree->pred_ub[mip->m+j] = col->ub;
+               tree->pred_stat[mip->m+j] = (char)col->stat;
+            }
+         }
+         /* change bounds of rows and columns */
+         {  IOSBND *b;
+            for (b = node->b_ptr; b != NULL; b = b->next)
+            {  if (b->k <= m)
+                  glp_set_row_bnds(mip, b->k, b->type, b->lb, b->ub);
+               else
+                  glp_set_col_bnds(mip, b->k-m, b->type, b->lb, b->ub);
+            }
+         }
+         /* change statuses of rows and columns */
+         {  IOSTAT *s;
+            for (s = node->s_ptr; s != NULL; s = s->next)
+            {  if (s->k <= m)
+                  glp_set_row_stat(mip, s->k, s->stat);
+               else
+                  glp_set_col_stat(mip, s->k-m, s->stat);
+            }
+         }
+         /* add new rows */
+         if (node->r_ptr != NULL)
+         {  IOSROW *r;
+            IOSAIJ *a;
+            int i, len, *ind;
+            double *val;
+            ind = xcalloc(1+n, sizeof(int));
+            val = xcalloc(1+n, sizeof(double));
+            for (r = node->r_ptr; r != NULL; r = r->next)
+            {  i = glp_add_rows(mip, 1);
+               glp_set_row_name(mip, i, r->name);
+#if 1 /* 20/IX-2008 */
+               xassert(mip->row[i]->level == 0);
+               mip->row[i]->level = node->level;
+               mip->row[i]->origin = r->origin;
+               mip->row[i]->klass = r->klass;
+#endif
+               glp_set_row_bnds(mip, i, r->type, r->lb, r->ub);
+               len = 0;
+               for (a = r->ptr; a != NULL; a = a->next)
+                  len++, ind[len] = a->j, val[len] = a->val;
+               glp_set_mat_row(mip, i, len, ind, val);
+               glp_set_rii(mip, i, r->rii);
+               glp_set_row_stat(mip, i, r->stat);
+            }
+            xfree(ind);
+            xfree(val);
+         }
+#if 0
+         /* add new edges to the conflict graph */
+         /* add new cliques to the conflict graph */
+         /* (not implemented yet) */
+         xassert(node->own_nn == 0);
+         xassert(node->own_nc == 0);
+         xassert(node->e_ptr == NULL);
+#endif
+      }
+      /* the specified subproblem has been revived */
+      node = tree->curr;
+      /* delete its bound change list */
+      while (node->b_ptr != NULL)
+      {  IOSBND *b;
+         b = node->b_ptr;
+         node->b_ptr = b->next;
+         dmp_free_atom(tree->pool, b, sizeof(IOSBND));
+      }
+      /* delete its status change list */
+      while (node->s_ptr != NULL)
+      {  IOSTAT *s;
+         s = node->s_ptr;
+         node->s_ptr = s->next;
+         dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
+      }
+#if 1 /* 20/XI-2009 */
+      /* delete its row addition list (additional rows may appear, for
+         example, due to branching on GUB constraints */
+      while (node->r_ptr != NULL)
+      {  IOSROW *r;
+         r = node->r_ptr;
+         node->r_ptr = r->next;
+         xassert(r->name == NULL);
+         while (r->ptr != NULL)
+         {  IOSAIJ *a;
+            a = r->ptr;
+            r->ptr = a->next;
+            dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
+         }
+         dmp_free_atom(tree->pool, r, sizeof(IOSROW));
+      }
+#endif
+done: return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_freeze_node - freeze current subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_freeze_node(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_freeze_node freezes the current subproblem. */
+
+void ios_freeze_node(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      IOSNPD *node;
+      /* obtain pointer to the current subproblem */
+      node = tree->curr;
+      xassert(node != NULL);
+      if (node->up == NULL)
+      {  /* freeze the root subproblem */
+         int k;
+         xassert(node->p == 1);
+         xassert(tree->root_m == 0);
+         xassert(tree->root_type == NULL);
+         xassert(tree->root_lb == NULL);
+         xassert(tree->root_ub == NULL);
+         xassert(tree->root_stat == NULL);
+         tree->root_m = m;
+         tree->root_type = xcalloc(1+m+n, sizeof(char));
+         tree->root_lb = xcalloc(1+m+n, sizeof(double));
+         tree->root_ub = xcalloc(1+m+n, sizeof(double));
+         tree->root_stat = xcalloc(1+m+n, sizeof(char));
+         for (k = 1; k <= m+n; k++)
+         {  if (k <= m)
+            {  GLPROW *row = mip->row[k];
+               tree->root_type[k] = (char)row->type;
+               tree->root_lb[k] = row->lb;
+               tree->root_ub[k] = row->ub;
+               tree->root_stat[k] = (char)row->stat;
+            }
+            else
+            {  GLPCOL *col = mip->col[k-m];
+               tree->root_type[k] = (char)col->type;
+               tree->root_lb[k] = col->lb;
+               tree->root_ub[k] = col->ub;
+               tree->root_stat[k] = (char)col->stat;
+            }
+         }
+      }
+      else
+      {  /* freeze non-root subproblem */
+         int root_m = tree->root_m;
+         int pred_m = tree->pred_m;
+         int i, j, k;
+         xassert(pred_m <= m);
+         /* build change lists for rows and columns which exist in the
+            parent subproblem */
+         xassert(node->b_ptr == NULL);
+         xassert(node->s_ptr == NULL);
+         for (k = 1; k <= pred_m + n; k++)
+         {  int pred_type, pred_stat, type, stat;
+            double pred_lb, pred_ub, lb, ub;
+            /* determine attributes in the parent subproblem */
+            pred_type = tree->pred_type[k];
+            pred_lb = tree->pred_lb[k];
+            pred_ub = tree->pred_ub[k];
+            pred_stat = tree->pred_stat[k];
+            /* determine attributes in the current subproblem */
+            if (k <= pred_m)
+            {  GLPROW *row = mip->row[k];
+               type = row->type;
+               lb = row->lb;
+               ub = row->ub;
+               stat = row->stat;
+            }
+            else
+            {  GLPCOL *col = mip->col[k - pred_m];
+               type = col->type;
+               lb = col->lb;
+               ub = col->ub;
+               stat = col->stat;
+            }
+            /* save type and bounds of a row/column, if changed */
+            if (!(pred_type == type && pred_lb == lb && pred_ub == ub))
+            {  IOSBND *b;
+               b = dmp_get_atom(tree->pool, sizeof(IOSBND));
+               b->k = k;
+               b->type = (unsigned char)type;
+               b->lb = lb;
+               b->ub = ub;
+               b->next = node->b_ptr;
+               node->b_ptr = b;
+            }
+            /* save status of a row/column, if changed */
+            if (pred_stat != stat)
+            {  IOSTAT *s;
+               s = dmp_get_atom(tree->pool, sizeof(IOSTAT));
+               s->k = k;
+               s->stat = (unsigned char)stat;
+               s->next = node->s_ptr;
+               node->s_ptr = s;
+            }
+         }
+         /* save new rows added to the current subproblem */
+         xassert(node->r_ptr == NULL);
+         if (pred_m < m)
+         {  int i, len, *ind;
+            double *val;
+            ind = xcalloc(1+n, sizeof(int));
+            val = xcalloc(1+n, sizeof(double));
+            for (i = m; i > pred_m; i--)
+            {  GLPROW *row = mip->row[i];
+               IOSROW *r;
+               const char *name;
+               r = dmp_get_atom(tree->pool, sizeof(IOSROW));
+               name = glp_get_row_name(mip, i);
+               if (name == NULL)
+                  r->name = NULL;
+               else
+               {  r->name = dmp_get_atom(tree->pool, strlen(name)+1);
+                  strcpy(r->name, name);
+               }
+#if 1 /* 20/IX-2008 */
+               r->origin = row->origin;
+               r->klass = row->klass;
+#endif
+               r->type = (unsigned char)row->type;
+               r->lb = row->lb;
+               r->ub = row->ub;
+               r->ptr = NULL;
+               len = glp_get_mat_row(mip, i, ind, val);
+               for (k = 1; k <= len; k++)
+               {  IOSAIJ *a;
+                  a = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
+                  a->j = ind[k];
+                  a->val = val[k];
+                  a->next = r->ptr;
+                  r->ptr = a;
+               }
+               r->rii = row->rii;
+               r->stat = (unsigned char)row->stat;
+               r->next = node->r_ptr;
+               node->r_ptr = r;
+            }
+            xfree(ind);
+            xfree(val);
+         }
+         /* remove all rows missing in the root subproblem */
+         if (m != root_m)
+         {  int nrs, *num;
+            nrs = m - root_m;
+            xassert(nrs > 0);
+            num = xcalloc(1+nrs, sizeof(int));
+            for (i = 1; i <= nrs; i++) num[i] = root_m + i;
+            glp_del_rows(mip, nrs, num);
+            xfree(num);
+         }
+         m = mip->m;
+         /* and restore attributes of all rows and columns for the root
+            subproblem */
+         xassert(m == root_m);
+         for (i = 1; i <= m; i++)
+         {  glp_set_row_bnds(mip, i, tree->root_type[i],
+               tree->root_lb[i], tree->root_ub[i]);
+            glp_set_row_stat(mip, i, tree->root_stat[i]);
+         }
+         for (j = 1; j <= n; j++)
+         {  glp_set_col_bnds(mip, j, tree->root_type[m+j],
+               tree->root_lb[m+j], tree->root_ub[m+j]);
+            glp_set_col_stat(mip, j, tree->root_stat[m+j]);
+         }
+#if 1
+         /* remove all edges and cliques missing in the conflict graph
+            for the root subproblem */
+         /* (not implemented yet) */
+#endif
+      }
+      /* the current subproblem has been frozen */
+      tree->curr = NULL;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clone_node - clone specified subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clone_node clones the specified subproblem, whose
+*  reference number is p, creating its nnn exact copies. Note that the
+*  specified subproblem must be active and must be in the frozen state
+*  (i.e. it must not be the current subproblem).
+*
+*  Each clone, an exact copy of the specified subproblem, becomes a new
+*  active subproblem added to the end of the active list. After cloning
+*  the specified subproblem becomes inactive.
+*
+*  The reference numbers of clone subproblems are stored to locations
+*  ref[1], ..., ref[nnn]. */
+
+static int get_slot(glp_tree *tree)
+{     int p;
+      /* if no free slots are available, increase the room */
+      if (tree->avail == 0)
+      {  int nslots = tree->nslots;
+         IOSLOT *save = tree->slot;
+         if (nslots == 0)
+            tree->nslots = 20;
+         else
+         {  tree->nslots = nslots + nslots;
+            xassert(tree->nslots > nslots);
+         }
+         tree->slot = xcalloc(1+tree->nslots, sizeof(IOSLOT));
+         if (save != NULL)
+         {  memcpy(&tree->slot[1], &save[1], nslots * sizeof(IOSLOT));
+            xfree(save);
+         }
+         /* push more free slots into the stack */
+         for (p = tree->nslots; p > nslots; p--)
+         {  tree->slot[p].node = NULL;
+            tree->slot[p].next = tree->avail;
+            tree->avail = p;
+         }
+      }
+      /* pull a free slot from the stack */
+      p = tree->avail;
+      tree->avail = tree->slot[p].next;
+      xassert(tree->slot[p].node == NULL);
+      tree->slot[p].next = 0;
+      return p;
+}
+
+static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent)
+{     IOSNPD *node;
+      int p;
+      /* pull a free slot for the new node */
+      p = get_slot(tree);
+      /* create descriptor of the new subproblem */
+      node = dmp_get_atom(tree->pool, sizeof(IOSNPD));
+      tree->slot[p].node = node;
+      node->p = p;
+      node->up = parent;
+      node->level = (parent == NULL ? 0 : parent->level + 1);
+      node->count = 0;
+      node->b_ptr = NULL;
+      node->s_ptr = NULL;
+      node->r_ptr = NULL;
+      node->solved = 0;
+#if 0
+      node->own_nn = node->own_nc = 0;
+      node->e_ptr = NULL;
+#endif
+#if 1 /* 04/X-2008 */
+      node->lp_obj = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
+         -DBL_MAX : +DBL_MAX) : parent->lp_obj);
+#endif
+      node->bound = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
+         -DBL_MAX : +DBL_MAX) : parent->bound);
+      node->br_var = 0;
+      node->br_val = 0.0;
+      node->ii_cnt = 0;
+      node->ii_sum = 0.0;
+#if 1 /* 30/XI-2009 */
+      node->changed = 0;
+#endif
+      if (tree->parm->cb_size == 0)
+         node->data = NULL;
+      else
+      {  node->data = dmp_get_atom(tree->pool, tree->parm->cb_size);
+         memset(node->data, 0, tree->parm->cb_size);
+      }
+      node->temp = NULL;
+      node->prev = tree->tail;
+      node->next = NULL;
+      /* add the new subproblem to the end of the active list */
+      if (tree->head == NULL)
+         tree->head = node;
+      else
+         tree->tail->next = node;
+      tree->tail = node;
+      tree->a_cnt++;
+      tree->n_cnt++;
+      tree->t_cnt++;
+      /* increase the number of child subproblems */
+      if (parent == NULL)
+         xassert(p == 1);
+      else
+         parent->count++;
+      return node;
+}
+
+void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[])
+{     IOSNPD *node;
+      int k;
+      /* obtain pointer to the subproblem to be cloned */
+      xassert(1 <= p && p <= tree->nslots);
+      node = tree->slot[p].node;
+      xassert(node != NULL);
+      /* the specified subproblem must be active */
+      xassert(node->count == 0);
+      /* and must be in the frozen state */
+      xassert(tree->curr != node);
+      /* remove the specified subproblem from the active list, because
+         it becomes inactive */
+      if (node->prev == NULL)
+         tree->head = node->next;
+      else
+         node->prev->next = node->next;
+      if (node->next == NULL)
+         tree->tail = node->prev;
+      else
+         node->next->prev = node->prev;
+      node->prev = node->next = NULL;
+      tree->a_cnt--;
+      /* create clone subproblems */
+      xassert(nnn > 0);
+      for (k = 1; k <= nnn; k++)
+         ref[k] = new_node(tree, node)->p;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_delete_node - delete specified subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_delete_node(glp_tree *tree, int p);
+*
+*  DESCRIPTION
+*
+*  The routine ios_delete_node deletes the specified subproblem, whose
+*  reference number is p. The subproblem must be active and must be in
+*  the frozen state (i.e. it must not be the current subproblem).
+*
+*  Note that deletion is performed recursively, i.e. if a subproblem to
+*  be deleted is the only child of its parent, the parent subproblem is
+*  also deleted, etc. */
+
+void ios_delete_node(glp_tree *tree, int p)
+{     IOSNPD *node, *temp;
+      /* obtain pointer to the subproblem to be deleted */
+      xassert(1 <= p && p <= tree->nslots);
+      node = tree->slot[p].node;
+      xassert(node != NULL);
+      /* the specified subproblem must be active */
+      xassert(node->count == 0);
+      /* and must be in the frozen state */
+      xassert(tree->curr != node);
+      /* remove the specified subproblem from the active list, because
+         it is gone from the tree */
+      if (node->prev == NULL)
+         tree->head = node->next;
+      else
+         node->prev->next = node->next;
+      if (node->next == NULL)
+         tree->tail = node->prev;
+      else
+         node->next->prev = node->prev;
+      node->prev = node->next = NULL;
+      tree->a_cnt--;
+loop: /* recursive deletion starts here */
+      /* delete the bound change list */
+      {  IOSBND *b;
+         while (node->b_ptr != NULL)
+         {  b = node->b_ptr;
+            node->b_ptr = b->next;
+            dmp_free_atom(tree->pool, b, sizeof(IOSBND));
+         }
+      }
+      /* delete the status change list */
+      {  IOSTAT *s;
+         while (node->s_ptr != NULL)
+         {  s = node->s_ptr;
+            node->s_ptr = s->next;
+            dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
+         }
+      }
+      /* delete the row addition list */
+      while (node->r_ptr != NULL)
+      {  IOSROW *r;
+         r = node->r_ptr;
+         if (r->name != NULL)
+            dmp_free_atom(tree->pool, r->name, strlen(r->name)+1);
+         while (r->ptr != NULL)
+         {  IOSAIJ *a;
+            a = r->ptr;
+            r->ptr = a->next;
+            dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
+         }
+         node->r_ptr = r->next;
+         dmp_free_atom(tree->pool, r, sizeof(IOSROW));
+      }
+#if 0
+      /* delete the edge addition list */
+      /* delete the clique addition list */
+      /* (not implemented yet) */
+      xassert(node->own_nn == 0);
+      xassert(node->own_nc == 0);
+      xassert(node->e_ptr == NULL);
+#endif
+      /* free application-specific data */
+      if (tree->parm->cb_size == 0)
+         xassert(node->data == NULL);
+      else
+         dmp_free_atom(tree->pool, node->data, tree->parm->cb_size);
+      /* free the corresponding node slot */
+      p = node->p;
+      xassert(tree->slot[p].node == node);
+      tree->slot[p].node = NULL;
+      tree->slot[p].next = tree->avail;
+      tree->avail = p;
+      /* save pointer to the parent subproblem */
+      temp = node->up;
+      /* delete the subproblem descriptor */
+      dmp_free_atom(tree->pool, node, sizeof(IOSNPD));
+      tree->n_cnt--;
+      /* take pointer to the parent subproblem */
+      node = temp;
+      if (node != NULL)
+      {  /* the parent subproblem exists; decrease the number of its
+            child subproblems */
+         xassert(node->count > 0);
+         node->count--;
+         /* if now the parent subproblem has no childs, it also must be
+            deleted */
+         if (node->count == 0) goto loop;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_delete_tree - delete branch-and-bound tree
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_delete_tree(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_delete_tree deletes the branch-and-bound tree, which
+*  the parameter tree points to, and frees all the memory allocated to
+*  this program object.
+*
+*  On exit components of the problem object are restored to correspond
+*  to the original MIP passed to the routine ios_create_tree. */
+
+void ios_delete_tree(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      int i, j;
+      int m = mip->m;
+      int n = mip->n;
+      xassert(mip->tree == tree);
+      /* remove all additional rows */
+      if (m != tree->orig_m)
+      {  int nrs, *num;
+         nrs = m - tree->orig_m;
+         xassert(nrs > 0);
+         num = xcalloc(1+nrs, sizeof(int));
+         for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i;
+         glp_del_rows(mip, nrs, num);
+         xfree(num);
+      }
+      m = tree->orig_m;
+      /* restore original attributes of rows and columns */
+      xassert(m == tree->orig_m);
+      xassert(n == tree->n);
+      for (i = 1; i <= m; i++)
+      {  glp_set_row_bnds(mip, i, tree->orig_type[i],
+            tree->orig_lb[i], tree->orig_ub[i]);
+         glp_set_row_stat(mip, i, tree->orig_stat[i]);
+         mip->row[i]->prim = tree->orig_prim[i];
+         mip->row[i]->dual = tree->orig_dual[i];
+      }
+      for (j = 1; j <= n; j++)
+      {  glp_set_col_bnds(mip, j, tree->orig_type[m+j],
+            tree->orig_lb[m+j], tree->orig_ub[m+j]);
+         glp_set_col_stat(mip, j, tree->orig_stat[m+j]);
+         mip->col[j]->prim = tree->orig_prim[m+j];
+         mip->col[j]->dual = tree->orig_dual[m+j];
+      }
+      mip->pbs_stat = mip->dbs_stat = GLP_FEAS;
+      mip->obj_val = tree->orig_obj;
+      /* delete the branch-and-bound tree */
+      xassert(tree->local != NULL);
+      ios_delete_pool(tree, tree->local);
+      dmp_delete_pool(tree->pool);
+      xfree(tree->orig_type);
+      xfree(tree->orig_lb);
+      xfree(tree->orig_ub);
+      xfree(tree->orig_stat);
+      xfree(tree->orig_prim);
+      xfree(tree->orig_dual);
+      xfree(tree->slot);
+      if (tree->root_type != NULL) xfree(tree->root_type);
+      if (tree->root_lb != NULL) xfree(tree->root_lb);
+      if (tree->root_ub != NULL) xfree(tree->root_ub);
+      if (tree->root_stat != NULL) xfree(tree->root_stat);
+      xfree(tree->non_int);
+#if 0
+      xfree(tree->n_ref);
+      xfree(tree->c_ref);
+      xfree(tree->j_ref);
+#endif
+      if (tree->pcost != NULL) ios_pcost_free(tree);
+      xfree(tree->iwrk);
+      xfree(tree->dwrk);
+#if 0
+      scg_delete_graph(tree->g);
+#endif
+      if (tree->pred_type != NULL) xfree(tree->pred_type);
+      if (tree->pred_lb != NULL) xfree(tree->pred_lb);
+      if (tree->pred_ub != NULL) xfree(tree->pred_ub);
+      if (tree->pred_stat != NULL) xfree(tree->pred_stat);
+#if 0
+      xassert(tree->cut_gen == NULL);
+#endif
+      xassert(tree->mir_gen == NULL);
+      xassert(tree->clq_gen == NULL);
+      xfree(tree);
+      mip->tree = NULL;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_eval_degrad - estimate obj. degrad. for down- and up-branches
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
+*
+*  DESCRIPTION
+*
+*  Given optimal basis to LP relaxation of the current subproblem the
+*  routine ios_eval_degrad performs the dual ratio test to compute the
+*  objective values in the adjacent basis for down- and up-branches,
+*  which are stored in locations *dn and *up, assuming that x[j] is a
+*  variable chosen to branch upon. */
+
+void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up)
+{     glp_prob *mip = tree->mip;
+      int m = mip->m, n = mip->n;
+      int len, kase, k, t, stat;
+      double alfa, beta, gamma, delta, dz;
+      int *ind = tree->iwrk;
+      double *val = tree->dwrk;
+      /* current basis must be optimal */
+      xassert(glp_get_status(mip) == GLP_OPT);
+      /* basis factorization must exist */
+      xassert(glp_bf_exists(mip));
+      /* obtain (fractional) value of x[j] in optimal basic solution
+         to LP relaxation of the current subproblem */
+      xassert(1 <= j && j <= n);
+      beta = mip->col[j]->prim;
+      /* since the value of x[j] is fractional, it is basic; compute
+         corresponding row of the simplex table */
+      len = lpx_eval_tab_row(mip, m+j, ind, val);
+      /* kase < 0 means down-branch; kase > 0 means up-branch */
+      for (kase = -1; kase <= +1; kase += 2)
+      {  /* for down-branch we introduce new upper bound floor(beta)
+            for x[j]; similarly, for up-branch we introduce new lower
+            bound ceil(beta) for x[j]; in the current basis this new
+            upper/lower bound is violated, so in the adjacent basis
+            x[j] will leave the basis and go to its new upper/lower
+            bound; we need to know which non-basic variable x[k] should
+            enter the basis to keep dual feasibility */
+#if 0 /* 23/XI-2009 */
+         k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-7);
+#else
+         k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-9);
+#endif
+         /* if no variable has been chosen, current basis being primal
+            infeasible due to the new upper/lower bound of x[j] is dual
+            unbounded, therefore, LP relaxation to corresponding branch
+            has no primal feasible solution */
+         if (k == 0)
+         {  if (mip->dir == GLP_MIN)
+            {  if (kase < 0)
+                  *dn = +DBL_MAX;
+               else
+                  *up = +DBL_MAX;
+            }
+            else if (mip->dir == GLP_MAX)
+            {  if (kase < 0)
+                  *dn = -DBL_MAX;
+               else
+                  *up = -DBL_MAX;
+            }
+            else
+               xassert(mip != mip);
+            continue;
+         }
+         xassert(1 <= k && k <= m+n);
+         /* row of the simplex table corresponding to specified basic
+            variable x[j] is the following:
+               x[j] = ... + alfa * x[k] + ... ;
+            we need to know influence coefficient, alfa, at non-basic
+            variable x[k] chosen with the dual ratio test */
+         for (t = 1; t <= len; t++)
+            if (ind[t] == k) break;
+         xassert(1 <= t && t <= len);
+         alfa = val[t];
+         /* determine status and reduced cost of variable x[k] */
+         if (k <= m)
+         {  stat = mip->row[k]->stat;
+            gamma = mip->row[k]->dual;
+         }
+         else
+         {  stat = mip->col[k-m]->stat;
+            gamma = mip->col[k-m]->dual;
+         }
+         /* x[k] cannot be basic or fixed non-basic */
+         xassert(stat == GLP_NL || stat == GLP_NU || stat == GLP_NF);
+         /* if the current basis is dual degenerative, some reduced
+            costs, which are close to zero, may have wrong sign due to
+            round-off errors, so correct the sign of gamma */
+         if (mip->dir == GLP_MIN)
+         {  if (stat == GLP_NL && gamma < 0.0 ||
+                stat == GLP_NU && gamma > 0.0 ||
+                stat == GLP_NF) gamma = 0.0;
+         }
+         else if (mip->dir == GLP_MAX)
+         {  if (stat == GLP_NL && gamma > 0.0 ||
+                stat == GLP_NU && gamma < 0.0 ||
+                stat == GLP_NF) gamma = 0.0;
+         }
+         else
+            xassert(mip != mip);
+         /* determine the change of x[j] in the adjacent basis:
+            delta x[j] = new x[j] - old x[j] */
+         delta = (kase < 0 ? floor(beta) : ceil(beta)) - beta;
+         /* compute the change of x[k] in the adjacent basis:
+            delta x[k] = new x[k] - old x[k] = delta x[j] / alfa */
+         delta /= alfa;
+         /* compute the change of the objective in the adjacent basis:
+            delta z = new z - old z = gamma * delta x[k] */
+         dz = gamma * delta;
+         if (mip->dir == GLP_MIN)
+            xassert(dz >= 0.0);
+         else if (mip->dir == GLP_MAX)
+            xassert(dz <= 0.0);
+         else
+            xassert(mip != mip);
+         /* compute the new objective value in the adjacent basis:
+            new z = old z + delta z */
+         if (kase < 0)
+            *dn = mip->obj_val + dz;
+         else
+            *up = mip->obj_val + dz;
+      }
+      /*xprintf("obj = %g; dn = %g; up = %g\n",
+         mip->obj_val, *dn, *up);*/
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_round_bound - improve local bound by rounding
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  double ios_round_bound(glp_tree *tree, double bound);
+*
+*  RETURNS
+*
+*  For the given local bound for any integer feasible solution to the
+*  current subproblem the routine ios_round_bound returns an improved
+*  local bound for the same integer feasible solution.
+*
+*  BACKGROUND
+*
+*  Let the current subproblem has the following objective function:
+*
+*     z =   sum  c[j] * x[j] + s >= b,                               (1)
+*         j in J
+*
+*  where J = {j: c[j] is non-zero and integer, x[j] is integer}, s is
+*  the sum of terms corresponding to fixed variables, b is an initial
+*  local bound (minimization).
+*
+*  From (1) it follows that:
+*
+*     d *  sum  (c[j] / d) * x[j] + s >= b,                          (2)
+*        j in J
+*
+*  or, equivalently,
+*
+*     sum  (c[j] / d) * x[j] >= (b - s) / d = h,                     (3)
+*   j in J
+*
+*  where d = gcd(c[j]). Since the left-hand side of (3) is integer,
+*  h = (b - s) / d can be rounded up to the nearest integer:
+*
+*     h' = ceil(h) = (b' - s) / d,                                   (4)
+*
+*  that gives an rounded, improved local bound:
+*
+*     b' = d * h' + s.                                               (5)
+*
+*  In case of maximization '>=' in (1) should be replaced by '<=' that
+*  leads to the following formula:
+*
+*     h' = floor(h) = (b' - s) / d,                                  (6)
+*
+*  which should used in the same way as (4).
+*
+*  NOTE: If b is a valid local bound for a child of the current
+*        subproblem, b' is also valid for that child subproblem. */
+
+double ios_round_bound(glp_tree *tree, double bound)
+{     glp_prob *mip = tree->mip;
+      int n = mip->n;
+      int d, j, nn, *c = tree->iwrk;
+      double s, h;
+      /* determine c[j] and compute s */
+      nn = 0, s = mip->c0, d = 0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         if (col->coef == 0.0) continue;
+         if (col->type == GLP_FX)
+         {  /* fixed variable */
+            s += col->coef * col->prim;
+         }
+         else
+         {  /* non-fixed variable */
+            if (col->kind != GLP_IV) goto skip;
+            if (col->coef != floor(col->coef)) goto skip;
+            if (fabs(col->coef) <= (double)INT_MAX)
+               c[++nn] = (int)fabs(col->coef);
+            else
+               d = 1;
+         }
+      }
+      /* compute d = gcd(c[1],...c[nn]) */
+      if (d == 0)
+      {  if (nn == 0) goto skip;
+         d = gcdn(nn, c);
+      }
+      xassert(d > 0);
+      /* compute new local bound */
+      if (mip->dir == GLP_MIN)
+      {  if (bound != +DBL_MAX)
+         {  h = (bound - s) / (double)d;
+            if (h >= floor(h) + 0.001)
+            {  /* round up */
+               h = ceil(h);
+               /*xprintf("d = %d; old = %g; ", d, bound);*/
+               bound = (double)d * h + s;
+               /*xprintf("new = %g\n", bound);*/
+            }
+         }
+      }
+      else if (mip->dir == GLP_MAX)
+      {  if (bound != -DBL_MAX)
+         {  h = (bound - s) / (double)d;
+            if (h <= ceil(h) - 0.001)
+            {  /* round down */
+               h = floor(h);
+               bound = (double)d * h + s;
+            }
+         }
+      }
+      else
+         xassert(mip != mip);
+skip: return bound;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_is_hopeful - check if subproblem is hopeful
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_is_hopeful(glp_tree *tree, double bound);
+*
+*  DESCRIPTION
+*
+*  Given the local bound of a subproblem the routine ios_is_hopeful
+*  checks if the subproblem can have an integer optimal solution which
+*  is better than the best one currently known.
+*
+*  RETURNS
+*
+*  If the subproblem can have a better integer optimal solution, the
+*  routine returns non-zero; otherwise, if the corresponding branch can
+*  be pruned, the routine returns zero. */
+
+int ios_is_hopeful(glp_tree *tree, double bound)
+{     glp_prob *mip = tree->mip;
+      int ret = 1;
+      double eps;
+      if (mip->mip_stat == GLP_FEAS)
+      {  eps = tree->parm->tol_obj * (1.0 + fabs(mip->mip_obj));
+         switch (mip->dir)
+         {  case GLP_MIN:
+               if (bound >= mip->mip_obj - eps) ret = 0;
+               break;
+            case GLP_MAX:
+               if (bound <= mip->mip_obj + eps) ret = 0;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      else
+      {  switch (mip->dir)
+         {  case GLP_MIN:
+               if (bound == +DBL_MAX) ret = 0;
+               break;
+            case GLP_MAX:
+               if (bound == -DBL_MAX) ret = 0;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_best_node - find active node with best local bound
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_best_node(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_best_node finds an active node whose local bound is
+*  best among other active nodes.
+*
+*  It is understood that the integer optimal solution of the original
+*  mip problem cannot be better than the best bound, so the best bound
+*  is an lower (minimization) or upper (maximization) global bound for
+*  the original problem.
+*
+*  RETURNS
+*
+*  The routine ios_best_node returns the subproblem reference number
+*  for the best node. However, if the tree is empty, it returns zero. */
+
+int ios_best_node(glp_tree *tree)
+{     IOSNPD *node, *best = NULL;
+      switch (tree->mip->dir)
+      {  case GLP_MIN:
+            /* minimization */
+            for (node = tree->head; node != NULL; node = node->next)
+               if (best == NULL || best->bound > node->bound)
+                  best = node;
+            break;
+         case GLP_MAX:
+            /* maximization */
+            for (node = tree->head; node != NULL; node = node->next)
+               if (best == NULL || best->bound < node->bound)
+                  best = node;
+            break;
+         default:
+            xassert(tree != tree);
+      }
+      return best == NULL ? 0 : best->p;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_relative_gap - compute relative mip gap
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  double ios_relative_gap(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_relative_gap computes the relative mip gap using the
+*  formula:
+*
+*     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
+*
+*  where best_mip is the best integer feasible solution found so far,
+*  best_bnd is the best (global) bound. If no integer feasible solution
+*  has been found yet, rel_gap is set to DBL_MAX.
+*
+*  RETURNS
+*
+*  The routine ios_relative_gap returns the relative mip gap. */
+
+double ios_relative_gap(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      int p;
+      double best_mip, best_bnd, gap;
+      if (mip->mip_stat == GLP_FEAS)
+      {  best_mip = mip->mip_obj;
+         p = ios_best_node(tree);
+         if (p == 0)
+         {  /* the tree is empty */
+            gap = 0.0;
+         }
+         else
+         {  best_bnd = tree->slot[p].node->bound;
+            gap = fabs(best_mip - best_bnd) / (fabs(best_mip) +
+               DBL_EPSILON);
+         }
+      }
+      else
+      {  /* no integer feasible solution has been found yet */
+         gap = DBL_MAX;
+      }
+      return gap;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_solve_node - solve LP relaxation of current subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_solve_node(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_solve_node re-optimizes LP relaxation of the current
+*  subproblem using the dual simplex method.
+*
+*  RETURNS
+*
+*  The routine returns the code which is reported by glp_simplex. */
+
+int ios_solve_node(glp_tree *tree)
+{     glp_prob *mip = tree->mip;
+      glp_smcp parm;
+      int ret;
+      /* the current subproblem must exist */
+      xassert(tree->curr != NULL);
+      /* set some control parameters */
+      glp_init_smcp(&parm);
+      switch (tree->parm->msg_lev)
+      {  case GLP_MSG_OFF:
+            parm.msg_lev = GLP_MSG_OFF; break;
+         case GLP_MSG_ERR:
+            parm.msg_lev = GLP_MSG_ERR; break;
+         case GLP_MSG_ON:
+         case GLP_MSG_ALL:
+            parm.msg_lev = GLP_MSG_ON; break;
+         case GLP_MSG_DBG:
+            parm.msg_lev = GLP_MSG_ALL; break;
+         default:
+            xassert(tree != tree);
+      }
+      parm.meth = GLP_DUALP;
+      if (tree->parm->msg_lev < GLP_MSG_DBG)
+         parm.out_dly = tree->parm->out_dly;
+      else
+         parm.out_dly = 0;
+      /* if the incumbent objective value is already known, use it to
+         prematurely terminate the dual simplex search */
+      if (mip->mip_stat == GLP_FEAS)
+      {  switch (tree->mip->dir)
+         {  case GLP_MIN:
+               parm.obj_ul = mip->mip_obj;
+               break;
+            case GLP_MAX:
+               parm.obj_ll = mip->mip_obj;
+               break;
+            default:
+               xassert(mip != mip);
+         }
+      }
+      /* try to solve/re-optimize the LP relaxation */
+      ret = glp_simplex(mip, &parm);
+      tree->curr->solved++;
+#if 0
+      xprintf("ret = %d; status = %d; pbs = %d; dbs = %d; some = %d\n",
+         ret, glp_get_status(mip), mip->pbs_stat, mip->dbs_stat,
+         mip->some);
+      lpx_print_sol(mip, "sol");
+#endif
+      return ret;
+}
+
+/**********************************************************************/
+
+IOSPOOL *ios_create_pool(glp_tree *tree)
+{     /* create cut pool */
+      IOSPOOL *pool;
+#if 0
+      pool = dmp_get_atom(tree->pool, sizeof(IOSPOOL));
+#else
+      xassert(tree == tree);
+      pool = xmalloc(sizeof(IOSPOOL));
+#endif
+      pool->size = 0;
+      pool->head = pool->tail = NULL;
+      pool->ord = 0, pool->curr = NULL;
+      return pool;
+}
+
+int ios_add_row(glp_tree *tree, IOSPOOL *pool,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs)
+{     /* add row (constraint) to the cut pool */
+      IOSCUT *cut;
+      IOSAIJ *aij;
+      int k;
+      xassert(pool != NULL);
+      cut = dmp_get_atom(tree->pool, sizeof(IOSCUT));
+      if (name == NULL || name[0] == '\0')
+         cut->name = NULL;
+      else
+      {  for (k = 0; name[k] != '\0'; k++)
+         {  if (k == 256)
+               xerror("glp_ios_add_row: cut name too long\n");
+            if (iscntrl((unsigned char)name[k]))
+               xerror("glp_ios_add_row: cut name contains invalid chara"
+                  "cter(s)\n");
+         }
+         cut->name = dmp_get_atom(tree->pool, strlen(name)+1);
+         strcpy(cut->name, name);
+      }
+      if (!(0 <= klass && klass <= 255))
+         xerror("glp_ios_add_row: klass = %d; invalid cut class\n",
+            klass);
+      cut->klass = (unsigned char)klass;
+      if (flags != 0)
+         xerror("glp_ios_add_row: flags = %d; invalid cut flags\n",
+            flags);
+      cut->ptr = NULL;
+      if (!(0 <= len && len <= tree->n))
+         xerror("glp_ios_add_row: len = %d; invalid cut length\n",
+            len);
+      for (k = 1; k <= len; k++)
+      {  aij = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
+         if (!(1 <= ind[k] && ind[k] <= tree->n))
+            xerror("glp_ios_add_row: ind[%d] = %d; column index out of "
+               "range\n", k, ind[k]);
+         aij->j = ind[k];
+         aij->val = val[k];
+         aij->next = cut->ptr;
+         cut->ptr = aij;
+      }
+      if (!(type == GLP_LO || type == GLP_UP || type == GLP_FX))
+         xerror("glp_ios_add_row: type = %d; invalid cut type\n",
+            type);
+      cut->type = (unsigned char)type;
+      cut->rhs = rhs;
+      cut->prev = pool->tail;
+      cut->next = NULL;
+      if (cut->prev == NULL)
+         pool->head = cut;
+      else
+         cut->prev->next = cut;
+      pool->tail = cut;
+      pool->size++;
+      return pool->size;
+}
+
+IOSCUT *ios_find_row(IOSPOOL *pool, int i)
+{     /* find row (constraint) in the cut pool */
+      /* (smart linear search) */
+      xassert(pool != NULL);
+      xassert(1 <= i && i <= pool->size);
+      if (pool->ord == 0)
+      {  xassert(pool->curr == NULL);
+         pool->ord = 1;
+         pool->curr = pool->head;
+      }
+      xassert(pool->curr != NULL);
+      if (i < pool->ord)
+      {  if (i < pool->ord - i)
+         {  pool->ord = 1;
+            pool->curr = pool->head;
+            while (pool->ord != i)
+            {  pool->ord++;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->next;
+            }
+         }
+         else
+         {  while (pool->ord != i)
+            {  pool->ord--;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->prev;
+            }
+         }
+      }
+      else if (i > pool->ord)
+      {  if (i - pool->ord < pool->size - i)
+         {  while (pool->ord != i)
+            {  pool->ord++;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->next;
+            }
+         }
+         else
+         {  pool->ord = pool->size;
+            pool->curr = pool->tail;
+            while (pool->ord != i)
+            {  pool->ord--;
+               xassert(pool->curr != NULL);
+               pool->curr = pool->curr->prev;
+            }
+         }
+      }
+      xassert(pool->ord == i);
+      xassert(pool->curr != NULL);
+      return pool->curr;
+}
+
+void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i)
+{     /* remove row (constraint) from the cut pool */
+      IOSCUT *cut;
+      IOSAIJ *aij;
+      xassert(pool != NULL);
+      if (!(1 <= i && i <= pool->size))
+         xerror("glp_ios_del_row: i = %d; cut number out of range\n",
+            i);
+      cut = ios_find_row(pool, i);
+      xassert(pool->curr == cut);
+      if (cut->next != NULL)
+         pool->curr = cut->next;
+      else if (cut->prev != NULL)
+         pool->ord--, pool->curr = cut->prev;
+      else
+         pool->ord = 0, pool->curr = NULL;
+      if (cut->name != NULL)
+         dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
+      if (cut->prev == NULL)
+      {  xassert(pool->head == cut);
+         pool->head = cut->next;
+      }
+      else
+      {  xassert(cut->prev->next == cut);
+         cut->prev->next = cut->next;
+      }
+      if (cut->next == NULL)
+      {  xassert(pool->tail == cut);
+         pool->tail = cut->prev;
+      }
+      else
+      {  xassert(cut->next->prev == cut);
+         cut->next->prev = cut->prev;
+      }
+      while (cut->ptr != NULL)
+      {  aij = cut->ptr;
+         cut->ptr = aij->next;
+         dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
+      }
+      dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
+      pool->size--;
+      return;
+}
+
+void ios_clear_pool(glp_tree *tree, IOSPOOL *pool)
+{     /* remove all rows (constraints) from the cut pool */
+      xassert(pool != NULL);
+      while (pool->head != NULL)
+      {  IOSCUT *cut = pool->head;
+         pool->head = cut->next;
+         if (cut->name != NULL)
+            dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
+         while (cut->ptr != NULL)
+         {  IOSAIJ *aij = cut->ptr;
+            cut->ptr = aij->next;
+            dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
+         }
+         dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
+      }
+      pool->size = 0;
+      pool->head = pool->tail = NULL;
+      pool->ord = 0, pool->curr = NULL;
+      return;
+}
+
+void ios_delete_pool(glp_tree *tree, IOSPOOL *pool)
+{     /* delete cut pool */
+      xassert(pool != NULL);
+      ios_clear_pool(tree, pool);
+      xfree(pool);
+      return;
+}
+
+/**********************************************************************/
+
+#if 0
+static int refer_to_node(glp_tree *tree, int j)
+{     /* determine node number corresponding to binary variable x[j] or
+         its complement */
+      glp_prob *mip = tree->mip;
+      int n = mip->n;
+      int *ref;
+      if (j > 0)
+         ref = tree->n_ref;
+      else
+         ref = tree->c_ref, j = - j;
+      xassert(1 <= j && j <= n);
+      if (ref[j] == 0)
+      {  /* new node is needed */
+         SCG *g = tree->g;
+         int n_max = g->n_max;
+         ref[j] = scg_add_nodes(g, 1);
+         if (g->n_max > n_max)
+         {  int *save = tree->j_ref;
+            tree->j_ref = xcalloc(1+g->n_max, sizeof(int));
+            memcpy(&tree->j_ref[1], &save[1], g->n * sizeof(int));
+            xfree(save);
+         }
+         xassert(ref[j] == g->n);
+         tree->j_ref[ref[j]] = j;
+         xassert(tree->curr != NULL);
+         if (tree->curr->level > 0) tree->curr->own_nn++;
+      }
+      return ref[j];
+}
+#endif
+
+#if 0
+void ios_add_edge(glp_tree *tree, int j1, int j2)
+{     /* add new edge to the conflict graph */
+      glp_prob *mip = tree->mip;
+      int n = mip->n;
+      SCGRIB *e;
+      int first, i1, i2;
+      xassert(-n <= j1 && j1 <= +n && j1 != 0);
+      xassert(-n <= j2 && j2 <= +n && j2 != 0);
+      xassert(j1 != j2);
+      /* determine number of the first node, which was added for the
+         current subproblem */
+      xassert(tree->curr != NULL);
+      first = tree->g->n - tree->curr->own_nn + 1;
+      /* determine node numbers for both endpoints */
+      i1 = refer_to_node(tree, j1);
+      i2 = refer_to_node(tree, j2);
+      /* add edge (i1,i2) to the conflict graph */
+      e = scg_add_edge(tree->g, i1, i2);
+      /* if the current subproblem is not the root and both endpoints
+         were created on some previous levels, save the edge */
+      if (tree->curr->level > 0 && i1 < first && i2 < first)
+      {  IOSRIB *rib;
+         rib = dmp_get_atom(tree->pool, sizeof(IOSRIB));
+         rib->j1 = j1;
+         rib->j2 = j2;
+         rib->e = e;
+         rib->next = tree->curr->e_ptr;
+         tree->curr->e_ptr = rib;
+      }
+      return;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpios02.c
===================================================================
--- deps/glpk/src/glpios02.c	(revision 9)
+++ deps/glpk/src/glpios02.c	(revision 9)
@@ -0,0 +1,825 @@
+/* glpios02.c (preprocess current subproblem) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  prepare_row_info - prepare row info to determine implied bounds
+*
+*  Given a row (linear form)
+*
+*      n
+*     sum a[j] * x[j]                                                (1)
+*     j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]                                           (2)
+*
+*  this routine computes f_min, j_min, f_max, j_max needed to determine
+*  implied bounds.
+*
+*  ALGORITHM
+*
+*  Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
+*
+*  Parameters f_min and j_min are computed as follows:
+*
+*  1) if there is no x[k] such that k in J+ and l[k] = -inf or k in J-
+*     and u[k] = +inf, then
+*
+*     f_min :=   sum   a[j] * l[j] +   sum   a[j] * u[j]
+*              j in J+               j in J-
+*                                                                    (3)
+*     j_min := 0
+*
+*  2) if there is exactly one x[k] such that k in J+ and l[k] = -inf
+*     or k in J- and u[k] = +inf, then
+*
+*     f_min :=   sum       a[j] * l[j] +   sum       a[j] * u[j]
+*              j in J+\{k}               j in J-\{k}
+*                                                                    (4)
+*     j_min := k
+*
+*  3) if there are two or more x[k] such that k in J+ and l[k] = -inf
+*     or k in J- and u[k] = +inf, then
+*
+*     f_min := -inf
+*                                                                    (5)
+*     j_min := 0
+*
+*  Parameters f_max and j_max are computed in a similar way as follows:
+*
+*  1) if there is no x[k] such that k in J+ and u[k] = +inf or k in J-
+*     and l[k] = -inf, then
+*
+*     f_max :=   sum   a[j] * u[j] +   sum   a[j] * l[j]
+*              j in J+               j in J-
+*                                                                    (6)
+*     j_max := 0
+*
+*  2) if there is exactly one x[k] such that k in J+ and u[k] = +inf
+*     or k in J- and l[k] = -inf, then
+*
+*     f_max :=   sum       a[j] * u[j] +   sum       a[j] * l[j]
+*              j in J+\{k}               j in J-\{k}
+*                                                                    (7)
+*     j_max := k
+*
+*  3) if there are two or more x[k] such that k in J+ and u[k] = +inf
+*     or k in J- and l[k] = -inf, then
+*
+*     f_max := +inf
+*                                                                    (8)
+*     j_max := 0                                                      */
+
+struct f_info
+{     int j_min, j_max;
+      double f_min, f_max;
+};
+
+static void prepare_row_info(int n, const double a[], const double l[],
+      const double u[], struct f_info *f)
+{     int j, j_min, j_max;
+      double f_min, f_max;
+      xassert(n >= 0);
+      /* determine f_min and j_min */
+      f_min = 0.0, j_min = 0;
+      for (j = 1; j <= n; j++)
+      {  if (a[j] > 0.0)
+         {  if (l[j] == -DBL_MAX)
+            {  if (j_min == 0)
+                  j_min = j;
+               else
+               {  f_min = -DBL_MAX, j_min = 0;
+                  break;
+               }
+            }
+            else
+               f_min += a[j] * l[j];
+         }
+         else if (a[j] < 0.0)
+         {  if (u[j] == +DBL_MAX)
+            {  if (j_min == 0)
+                  j_min = j;
+               else
+               {  f_min = -DBL_MAX, j_min = 0;
+                  break;
+               }
+            }
+            else
+               f_min += a[j] * u[j];
+         }
+         else
+            xassert(a != a);
+      }
+      f->f_min = f_min, f->j_min = j_min;
+      /* determine f_max and j_max */
+      f_max = 0.0, j_max = 0;
+      for (j = 1; j <= n; j++)
+      {  if (a[j] > 0.0)
+         {  if (u[j] == +DBL_MAX)
+            {  if (j_max == 0)
+                  j_max = j;
+               else
+               {  f_max = +DBL_MAX, j_max = 0;
+                  break;
+               }
+            }
+            else
+               f_max += a[j] * u[j];
+         }
+         else if (a[j] < 0.0)
+         {  if (l[j] == -DBL_MAX)
+            {  if (j_max == 0)
+                  j_max = j;
+               else
+               {  f_max = +DBL_MAX, j_max = 0;
+                  break;
+               }
+            }
+            else
+               f_max += a[j] * l[j];
+         }
+         else
+            xassert(a != a);
+      }
+      f->f_max = f_max, f->j_max = j_max;
+      return;
+}
+
+/***********************************************************************
+*  row_implied_bounds - determine row implied bounds
+*
+*  Given a row (linear form)
+*
+*      n
+*     sum a[j] * x[j]
+*     j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  this routine determines implied bounds of the row.
+*
+*  ALGORITHM
+*
+*  Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}.
+*
+*  The implied lower bound of the row is computed as follows:
+*
+*     L' :=   sum   a[j] * l[j] +   sum   a[j] * u[j]                (9)
+*           j in J+               j in J-
+*
+*  and as it follows from (3), (4), and (5):
+*
+*     L' := if j_min = 0 then f_min else -inf                       (10)
+*
+*  The implied upper bound of the row is computed as follows:
+*
+*     U' :=   sum   a[j] * u[j] +   sum   a[j] * l[j]               (11)
+*           j in J+               j in J-
+*
+*  and as it follows from (6), (7), and (8):
+*
+*     U' := if j_max = 0 then f_max else +inf                       (12)
+*
+*  The implied bounds are stored in locations LL and UU. */
+
+static void row_implied_bounds(const struct f_info *f, double *LL,
+      double *UU)
+{     *LL = (f->j_min == 0 ? f->f_min : -DBL_MAX);
+      *UU = (f->j_max == 0 ? f->f_max : +DBL_MAX);
+      return;
+}
+
+/***********************************************************************
+*  col_implied_bounds - determine column implied bounds
+*
+*  Given a row (constraint)
+*
+*           n
+*     L <= sum a[j] * x[j] <= U                                     (13)
+*          j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  this routine determines implied bounds of variable x[k].
+*
+*  It is assumed that if L != -inf, the lower bound of the row can be
+*  active, and if U != +inf, the upper bound of the row can be active.
+*
+*  ALGORITHM
+*
+*  From (13) it follows that
+*
+*     L <= sum a[j] * x[j] + a[k] * x[k] <= U
+*          j!=k
+*  or
+*
+*     L - sum a[j] * x[j] <= a[k] * x[k] <= U - sum a[j] * x[j]
+*         j!=k                                  j!=k
+*
+*  Thus, if the row lower bound L can be active, implied lower bound of
+*  term a[k] * x[k] can be determined as follows:
+*
+*     ilb(a[k] * x[k]) = min(L - sum a[j] * x[j]) =
+*                                j!=k
+*                                                                   (14)
+*                      = L - max sum a[j] * x[j]
+*                            j!=k
+*
+*  where, as it follows from (6), (7), and (8)
+*
+*                           / f_max - a[k] * u[k], j_max = 0, a[k] > 0
+*                           |
+*                           | f_max - a[k] * l[k], j_max = 0, a[k] < 0
+*     max sum a[j] * x[j] = {
+*         j!=k              | f_max,               j_max = k
+*                           |
+*                           \ +inf,                j_max != 0
+*
+*  and if the upper bound U can be active, implied upper bound of term
+*  a[k] * x[k] can be determined as follows:
+*
+*     iub(a[k] * x[k]) = max(U - sum a[j] * x[j]) =
+*                                j!=k
+*                                                                   (15)
+*                      = U - min sum a[j] * x[j]
+*                            j!=k
+*
+*  where, as it follows from (3), (4), and (5)
+*
+*                           / f_min - a[k] * l[k], j_min = 0, a[k] > 0
+*                           |
+*                           | f_min - a[k] * u[k], j_min = 0, a[k] < 0
+*     min sum a[j] * x[j] = {
+*         j!=k              | f_min,               j_min = k
+*                           |
+*                           \ -inf,                j_min != 0
+*
+*  Since
+*
+*     ilb(a[k] * x[k]) <= a[k] * x[k] <= iub(a[k] * x[k])
+*
+*  implied lower and upper bounds of x[k] are determined as follows:
+*
+*     l'[k] := if a[k] > 0 then ilb / a[k] else ulb / a[k]          (16)
+*
+*     u'[k] := if a[k] > 0 then ulb / a[k] else ilb / a[k]          (17)
+*
+*  The implied bounds are stored in locations ll and uu. */
+
+static void col_implied_bounds(const struct f_info *f, int n,
+      const double a[], double L, double U, const double l[],
+      const double u[], int k, double *ll, double *uu)
+{     double ilb, iub;
+      xassert(n >= 0);
+      xassert(1 <= k && k <= n);
+      /* determine implied lower bound of term a[k] * x[k] (14) */
+      if (L == -DBL_MAX || f->f_max == +DBL_MAX)
+         ilb = -DBL_MAX;
+      else if (f->j_max == 0)
+      {  if (a[k] > 0.0)
+         {  xassert(u[k] != +DBL_MAX);
+            ilb = L - (f->f_max - a[k] * u[k]);
+         }
+         else if (a[k] < 0.0)
+         {  xassert(l[k] != -DBL_MAX);
+            ilb = L - (f->f_max - a[k] * l[k]);
+         }
+         else
+            xassert(a != a);
+      }
+      else if (f->j_max == k)
+         ilb = L - f->f_max;
+      else
+         ilb = -DBL_MAX;
+      /* determine implied upper bound of term a[k] * x[k] (15) */
+      if (U == +DBL_MAX || f->f_min == -DBL_MAX)
+         iub = +DBL_MAX;
+      else if (f->j_min == 0)
+      {  if (a[k] > 0.0)
+         {  xassert(l[k] != -DBL_MAX);
+            iub = U - (f->f_min - a[k] * l[k]);
+         }
+         else if (a[k] < 0.0)
+         {  xassert(u[k] != +DBL_MAX);
+            iub = U - (f->f_min - a[k] * u[k]);
+         }
+         else
+            xassert(a != a);
+      }
+      else if (f->j_min == k)
+         iub = U - f->f_min;
+      else
+         iub = +DBL_MAX;
+      /* determine implied bounds of x[k] (16) and (17) */
+#if 1
+      /* do not use a[k] if it has small magnitude to prevent wrong
+         implied bounds; for example, 1e-15 * x1 >= x2 + x3, where
+         x1 >= -10, x2, x3 >= 0, would lead to wrong conclusion that
+         x1 >= 0 */
+      if (fabs(a[k]) < 1e-6)
+         *ll = -DBL_MAX, *uu = +DBL_MAX; else
+#endif
+      if (a[k] > 0.0)
+      {  *ll = (ilb == -DBL_MAX ? -DBL_MAX : ilb / a[k]);
+         *uu = (iub == +DBL_MAX ? +DBL_MAX : iub / a[k]);
+      }
+      else if (a[k] < 0.0)
+      {  *ll = (iub == +DBL_MAX ? -DBL_MAX : iub / a[k]);
+         *uu = (ilb == -DBL_MAX ? +DBL_MAX : ilb / a[k]);
+      }
+      else
+         xassert(a != a);
+      return;
+}
+
+/***********************************************************************
+*  check_row_bounds - check and relax original row bounds
+*
+*  Given a row (constraint)
+*
+*           n
+*     L <= sum a[j] * x[j] <= U
+*          j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  this routine checks the original row bounds L and U for feasibility
+*  and redundancy. If the original lower bound L or/and upper bound U
+*  cannot be active due to bounds of variables, the routine remove them
+*  replacing by -inf or/and +inf, respectively.
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+static int check_row_bounds(const struct f_info *f, double *L_,
+      double *U_)
+{     int ret = 0;
+      double L = *L_, U = *U_, LL, UU;
+      /* determine implied bounds of the row */
+      row_implied_bounds(f, &LL, &UU);
+      /* check if the original lower bound is infeasible */
+      if (L != -DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(L));
+         if (UU < L - eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original upper bound is infeasible */
+      if (U != +DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(U));
+         if (LL > U + eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original lower bound is redundant */
+      if (L != -DBL_MAX)
+      {  double eps = 1e-12 * (1.0 + fabs(L));
+         if (LL > L - eps)
+         {  /* it cannot be active, so remove it */
+            *L_ = -DBL_MAX;
+         }
+      }
+      /* check if the original upper bound is redundant */
+      if (U != +DBL_MAX)
+      {  double eps = 1e-12 * (1.0 + fabs(U));
+         if (UU < U + eps)
+         {  /* it cannot be active, so remove it */
+            *U_ = +DBL_MAX;
+         }
+      }
+done: return ret;
+}
+
+/***********************************************************************
+*  check_col_bounds - check and tighten original column bounds
+*
+*  Given a row (constraint)
+*
+*           n
+*     L <= sum a[j] * x[j] <= U
+*          j=1
+*
+*  and bounds of columns (variables)
+*
+*     l[j] <= x[j] <= u[j]
+*
+*  for column (variable) x[j] this routine checks the original column
+*  bounds l[j] and u[j] for feasibility and redundancy. If the original
+*  lower bound l[j] or/and upper bound u[j] cannot be active due to
+*  bounds of the constraint and other variables, the routine tighten
+*  them replacing by corresponding implied bounds, if possible.
+*
+*  NOTE: It is assumed that if L != -inf, the row lower bound can be
+*        active, and if U != +inf, the row upper bound can be active.
+*
+*  The flag means that variable x[j] is required to be integer.
+*
+*  New actual bounds for x[j] are stored in locations lj and uj.
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+static int check_col_bounds(const struct f_info *f, int n,
+      const double a[], double L, double U, const double l[],
+      const double u[], int flag, int j, double *_lj, double *_uj)
+{     int ret = 0;
+      double lj, uj, ll, uu;
+      xassert(n >= 0);
+      xassert(1 <= j && j <= n);
+      lj = l[j], uj = u[j];
+      /* determine implied bounds of the column */
+      col_implied_bounds(f, n, a, L, U, l, u, j, &ll, &uu);
+      /* if x[j] is integral, round its implied bounds */
+      if (flag)
+      {  if (ll != -DBL_MAX)
+            ll = (ll - floor(ll) < 1e-3 ? floor(ll) : ceil(ll));
+         if (uu != +DBL_MAX)
+            uu = (ceil(uu) - uu < 1e-3 ? ceil(uu) : floor(uu));
+      }
+      /* check if the original lower bound is infeasible */
+      if (lj != -DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(lj));
+         if (uu < lj - eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original upper bound is infeasible */
+      if (uj != +DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(uj));
+         if (ll > uj + eps)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* check if the original lower bound is redundant */
+      if (ll != -DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(ll));
+         if (lj < ll - eps)
+         {  /* it cannot be active, so tighten it */
+            lj = ll;
+         }
+      }
+      /* check if the original upper bound is redundant */
+      if (uu != +DBL_MAX)
+      {  double eps = 1e-3 * (1.0 + fabs(uu));
+         if (uj > uu + eps)
+         {  /* it cannot be active, so tighten it */
+            uj = uu;
+         }
+      }
+      /* due to round-off errors it may happen that lj > uj (although
+         lj < uj + eps, since no primal infeasibility is detected), so
+         adjuct the new actual bounds to provide lj <= uj */
+      if (!(lj == -DBL_MAX || uj == +DBL_MAX))
+      {  double t1 = fabs(lj), t2 = fabs(uj);
+         double eps = 1e-10 * (1.0 + (t1 <= t2 ? t1 : t2));
+         if (lj > uj - eps)
+         {  if (lj == l[j])
+               uj = lj;
+            else if (uj == u[j])
+               lj = uj;
+            else if (t1 <= t2)
+               uj = lj;
+            else
+               lj = uj;
+         }
+      }
+      *_lj = lj, *_uj = uj;
+done: return ret;
+}
+
+/***********************************************************************
+*  check_efficiency - check if change in column bounds is efficient
+*
+*  Given the original bounds of a column l and u and its new actual
+*  bounds l' and u' (possibly tighten by the routine check_col_bounds)
+*  this routine checks if the change in the column bounds is efficient
+*  enough. If so, the routine returns non-zero, otherwise zero.
+*
+*  The flag means that the variable is required to be integer. */
+
+static int check_efficiency(int flag, double l, double u, double ll,
+      double uu)
+{     int eff = 0;
+      /* check efficiency for lower bound */
+      if (l < ll)
+      {  if (flag || l == -DBL_MAX)
+            eff++;
+         else
+         {  double r;
+            if (u == +DBL_MAX)
+               r = 1.0 + fabs(l);
+            else
+               r = 1.0 + (u - l);
+            if (ll - l >= 0.25 * r)
+               eff++;
+         }
+      }
+      /* check efficiency for upper bound */
+      if (u > uu)
+      {  if (flag || u == +DBL_MAX)
+            eff++;
+         else
+         {  double r;
+            if (l == -DBL_MAX)
+               r = 1.0 + fabs(u);
+            else
+               r = 1.0 + (u - l);
+            if (u - uu >= 0.25 * r)
+               eff++;
+         }
+      }
+      return eff;
+}
+
+/***********************************************************************
+*  basic_preprocessing - perform basic preprocessing
+*
+*  This routine performs basic preprocessing of the specified MIP that
+*  includes relaxing some row bounds and tightening some column bounds.
+*
+*  On entry the arrays L and U contains original row bounds, and the
+*  arrays l and u contains original column bounds:
+*
+*  L[0] is the lower bound of the objective row;
+*  L[i], i = 1,...,m, is the lower bound of i-th row;
+*  U[0] is the upper bound of the objective row;
+*  U[i], i = 1,...,m, is the upper bound of i-th row;
+*  l[0] is not used;
+*  l[j], j = 1,...,n, is the lower bound of j-th column;
+*  u[0] is not used;
+*  u[j], j = 1,...,n, is the upper bound of j-th column.
+*
+*  On exit the arrays L, U, l, and u contain new actual bounds of rows
+*  and column in the same locations.
+*
+*  The parameters nrs and num specify an initial list of rows to be
+*  processed:
+*
+*  nrs is the number of rows in the initial list, 0 <= nrs <= m+1;
+*  num[0] is not used;
+*  num[1,...,nrs] are row numbers (0 means the objective row).
+*
+*  The parameter max_pass specifies the maximal number of times that
+*  each row can be processed, max_pass > 0.
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+static int basic_preprocessing(glp_prob *mip, double L[], double U[],
+      double l[], double u[], int nrs, const int num[], int max_pass)
+{     int m = mip->m;
+      int n = mip->n;
+      struct f_info f;
+      int i, j, k, len, size, ret = 0;
+      int *ind, *list, *mark, *pass;
+      double *val, *lb, *ub;
+      xassert(0 <= nrs && nrs <= m+1);
+      xassert(max_pass > 0);
+      /* allocate working arrays */
+      ind = xcalloc(1+n, sizeof(int));
+      list = xcalloc(1+m+1, sizeof(int));
+      mark = xcalloc(1+m+1, sizeof(int));
+      memset(&mark[0], 0, (m+1) * sizeof(int));
+      pass = xcalloc(1+m+1, sizeof(int));
+      memset(&pass[0], 0, (m+1) * sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      lb = xcalloc(1+n, sizeof(double));
+      ub = xcalloc(1+n, sizeof(double));
+      /* initialize the list of rows to be processed */
+      size = 0;
+      for (k = 1; k <= nrs; k++)
+      {  i = num[k];
+         xassert(0 <= i && i <= m);
+         /* duplicate row numbers are not allowed */
+         xassert(!mark[i]);
+         list[++size] = i, mark[i] = 1;
+      }
+      xassert(size == nrs);
+      /* process rows in the list until it becomes empty */
+      while (size > 0)
+      {  /* get a next row from the list */
+         i = list[size--], mark[i] = 0;
+         /* increase the row processing count */
+         pass[i]++;
+         /* if the row is free, skip it */
+         if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
+         /* obtain coefficients of the row */
+         len = 0;
+         if (i == 0)
+         {  for (j = 1; j <= n; j++)
+            {  GLPCOL *col = mip->col[j];
+               if (col->coef != 0.0)
+                  len++, ind[len] = j, val[len] = col->coef;
+            }
+         }
+         else
+         {  GLPROW *row = mip->row[i];
+            GLPAIJ *aij;
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+               len++, ind[len] = aij->col->j, val[len] = aij->val;
+         }
+         /* determine lower and upper bounds of columns corresponding
+            to non-zero row coefficients */
+         for (k = 1; k <= len; k++)
+            j = ind[k], lb[k] = l[j], ub[k] = u[j];
+         /* prepare the row info to determine implied bounds */
+         prepare_row_info(len, val, lb, ub, &f);
+         /* check and relax bounds of the row */
+         if (check_row_bounds(&f, &L[i], &U[i]))
+         {  /* the feasible region is empty */
+            ret = 1;
+            goto done;
+         }
+         /* if the row became free, drop it */
+         if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue;
+         /* process columns having non-zero coefficients in the row */
+         for (k = 1; k <= len; k++)
+         {  GLPCOL *col;
+            int flag, eff;
+            double ll, uu;
+            /* take a next column in the row */
+            j = ind[k], col = mip->col[j];
+            flag = col->kind != GLP_CV;
+            /* check and tighten bounds of the column */
+            if (check_col_bounds(&f, len, val, L[i], U[i], lb, ub,
+                flag, k, &ll, &uu))
+            {  /* the feasible region is empty */
+               ret = 1;
+               goto done;
+            }
+            /* check if change in the column bounds is efficient */
+            eff = check_efficiency(flag, l[j], u[j], ll, uu);
+            /* set new actual bounds of the column */
+            l[j] = ll, u[j] = uu;
+            /* if the change is efficient, add all rows affected by the
+               corresponding column, to the list */
+            if (eff > 0)
+            {  GLPAIJ *aij;
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+               {  int ii = aij->row->i;
+                  /* if the row was processed maximal number of times,
+                     skip it */
+                  if (pass[ii] >= max_pass) continue;
+                  /* if the row is free, skip it */
+                  if (L[ii] == -DBL_MAX && U[ii] == +DBL_MAX) continue;
+                  /* put the row into the list */
+                  if (mark[ii] == 0)
+                  {  xassert(size <= m);
+                     list[++size] = ii, mark[ii] = 1;
+                  }
+               }
+            }
+         }
+      }
+done: /* free working arrays */
+      xfree(ind);
+      xfree(list);
+      xfree(mark);
+      xfree(pass);
+      xfree(val);
+      xfree(lb);
+      xfree(ub);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_preprocess_node - preprocess current subproblem
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_preprocess_node(glp_tree *tree, int max_pass);
+*
+*  DESCRIPTION
+*
+*  The routine ios_preprocess_node performs basic preprocessing of the
+*  current subproblem.
+*
+*  RETURNS
+*
+*  If no primal infeasibility is detected, the routine returns zero,
+*  otherwise non-zero. */
+
+int ios_preprocess_node(glp_tree *tree, int max_pass)
+{     glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      int i, j, nrs, *num, ret = 0;
+      double *L, *U, *l, *u;
+      /* the current subproblem must exist */
+      xassert(tree->curr != NULL);
+      /* determine original row bounds */
+      L = xcalloc(1+m, sizeof(double));
+      U = xcalloc(1+m, sizeof(double));
+      switch (mip->mip_stat)
+      {  case GLP_UNDEF:
+            L[0] = -DBL_MAX, U[0] = +DBL_MAX;
+            break;
+         case GLP_FEAS:
+            switch (mip->dir)
+            {  case GLP_MIN:
+                  L[0] = -DBL_MAX, U[0] = mip->mip_obj - mip->c0;
+                  break;
+               case GLP_MAX:
+                  L[0] = mip->mip_obj - mip->c0, U[0] = +DBL_MAX;
+                  break;
+               default:
+                  xassert(mip != mip);
+            }
+            break;
+         default:
+            xassert(mip != mip);
+      }
+      for (i = 1; i <= m; i++)
+      {  L[i] = glp_get_row_lb(mip, i);
+         U[i] = glp_get_row_ub(mip, i);
+      }
+      /* determine original column bounds */
+      l = xcalloc(1+n, sizeof(double));
+      u = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  l[j] = glp_get_col_lb(mip, j);
+         u[j] = glp_get_col_ub(mip, j);
+      }
+      /* build the initial list of rows to be analyzed */
+      nrs = m + 1;
+      num = xcalloc(1+nrs, sizeof(int));
+      for (i = 1; i <= nrs; i++) num[i] = i - 1;
+      /* perform basic preprocessing */
+      if (basic_preprocessing(mip , L, U, l, u, nrs, num, max_pass))
+      {  ret = 1;
+         goto done;
+      }
+      /* set new actual (relaxed) row bounds */
+      for (i = 1; i <= m; i++)
+      {  /* consider only non-active rows to keep dual feasibility */
+         if (glp_get_row_stat(mip, i) == GLP_BS)
+         {  if (L[i] == -DBL_MAX && U[i] == +DBL_MAX)
+               glp_set_row_bnds(mip, i, GLP_FR, 0.0, 0.0);
+            else if (U[i] == +DBL_MAX)
+               glp_set_row_bnds(mip, i, GLP_LO, L[i], 0.0);
+            else if (L[i] == -DBL_MAX)
+               glp_set_row_bnds(mip, i, GLP_UP, 0.0, U[i]);
+         }
+      }
+      /* set new actual (tightened) column bounds */
+      for (j = 1; j <= n; j++)
+      {  int type;
+         if (l[j] == -DBL_MAX && u[j] == +DBL_MAX)
+            type = GLP_FR;
+         else if (u[j] == +DBL_MAX)
+            type = GLP_LO;
+         else if (l[j] == -DBL_MAX)
+            type = GLP_UP;
+         else if (l[j] != u[j])
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(mip, j, type, l[j], u[j]);
+      }
+done: /* free working arrays and return */
+      xfree(L);
+      xfree(U);
+      xfree(l);
+      xfree(u);
+      xfree(num);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpios03.c
===================================================================
--- deps/glpk/src/glpios03.c	(revision 9)
+++ deps/glpk/src/glpios03.c	(revision 9)
@@ -0,0 +1,1155 @@
+/* glpios03.c (branch-and-cut driver) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  show_progress - display current progress of the search
+*
+*  This routine displays some information about current progress of the
+*  search.
+*
+*  The information includes:
+*
+*  the current number of iterations performed by the simplex solver;
+*
+*  the objective value for the best known integer feasible solution,
+*  which is upper (minimization) or lower (maximization) global bound
+*  for optimal solution of the original mip problem;
+*
+*  the best local bound for active nodes, which is lower (minimization)
+*  or upper (maximization) global bound for optimal solution of the
+*  original mip problem;
+*
+*  the relative mip gap, in percents;
+*
+*  the number of open (active) subproblems;
+*
+*  the number of completely explored subproblems, i.e. whose nodes have
+*  been removed from the tree. */
+
+static void show_progress(glp_tree *T, int bingo)
+{     int p;
+      double temp;
+      char best_mip[50], best_bound[50], *rho, rel_gap[50];
+      /* format the best known integer feasible solution */
+      if (T->mip->mip_stat == GLP_FEAS)
+         sprintf(best_mip, "%17.9e", T->mip->mip_obj);
+      else
+         sprintf(best_mip, "%17s", "not found yet");
+      /* determine reference number of an active subproblem whose local
+         bound is best */
+      p = ios_best_node(T);
+      /* format the best bound */
+      if (p == 0)
+         sprintf(best_bound, "%17s", "tree is empty");
+      else
+      {  temp = T->slot[p].node->bound;
+         if (temp == -DBL_MAX)
+            sprintf(best_bound, "%17s", "-inf");
+         else if (temp == +DBL_MAX)
+            sprintf(best_bound, "%17s", "+inf");
+         else
+            sprintf(best_bound, "%17.9e", temp);
+      }
+      /* choose the relation sign between global bounds */
+      if (T->mip->dir == GLP_MIN)
+         rho = ">=";
+      else if (T->mip->dir == GLP_MAX)
+         rho = "<=";
+      else
+         xassert(T != T);
+      /* format the relative mip gap */
+      temp = ios_relative_gap(T);
+      if (temp == 0.0)
+         sprintf(rel_gap, "  0.0%%");
+      else if (temp < 0.001)
+         sprintf(rel_gap, "< 0.1%%");
+      else if (temp <= 9.999)
+         sprintf(rel_gap, "%5.1f%%", 100.0 * temp);
+      else
+         sprintf(rel_gap, "%6s", "");
+      /* display progress of the search */
+      xprintf("+%6d: %s %s %s %s %s (%d; %d)\n",
+         T->mip->it_cnt, bingo ? ">>>>>" : "mip =", best_mip, rho,
+         best_bound, rel_gap, T->a_cnt, T->t_cnt - T->n_cnt);
+      T->tm_lag = xtime();
+      return;
+}
+
+/***********************************************************************
+*  is_branch_hopeful - check if specified branch is hopeful
+*
+*  This routine checks if the specified subproblem can have an integer
+*  optimal solution which is better than the best known one.
+*
+*  The check is based on comparison of the local objective bound stored
+*  in the subproblem descriptor and the incumbent objective value which
+*  is the global objective bound.
+*
+*  If there is a chance that the specified subproblem can have a better
+*  integer optimal solution, the routine returns non-zero. Otherwise, if
+*  the corresponding branch can pruned, zero is returned. */
+
+static int is_branch_hopeful(glp_tree *T, int p)
+{     xassert(1 <= p && p <= T->nslots);
+      xassert(T->slot[p].node != NULL);
+      return ios_is_hopeful(T, T->slot[p].node->bound);
+}
+
+/***********************************************************************
+*  check_integrality - check integrality of basic solution
+*
+*  This routine checks if the basic solution of LP relaxation of the
+*  current subproblem satisfies to integrality conditions, i.e. that all
+*  variables of integer kind have integral primal values. (The solution
+*  is assumed to be optimal.)
+*
+*  For each variable of integer kind the routine computes the following
+*  quantity:
+*
+*     ii(x[j]) = min(x[j] - floor(x[j]), ceil(x[j]) - x[j]),         (1)
+*
+*  which is a measure of the integer infeasibility (non-integrality) of
+*  x[j] (for example, ii(2.1) = 0.1, ii(3.7) = 0.3, ii(5.0) = 0). It is
+*  understood that 0 <= ii(x[j]) <= 0.5, and variable x[j] is integer
+*  feasible if ii(x[j]) = 0. However, due to floating-point arithmetic
+*  the routine checks less restrictive condition:
+*
+*     ii(x[j]) <= tol_int,                                           (2)
+*
+*  where tol_int is a given tolerance (small positive number) and marks
+*  each variable which does not satisfy to (2) as integer infeasible by
+*  setting its fractionality flag.
+*
+*  In order to characterize integer infeasibility of the basic solution
+*  in the whole the routine computes two parameters: ii_cnt, which is
+*  the number of variables with the fractionality flag set, and ii_sum,
+*  which is the sum of integer infeasibilities (1). */
+
+static void check_integrality(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int j, type, ii_cnt = 0;
+      double lb, ub, x, temp1, temp2, ii_sum = 0.0;
+      /* walk through the set of columns (structural variables) */
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         T->non_int[j] = 0;
+         /* if the column is not integer, skip it */
+         if (col->kind != GLP_IV) continue;
+         /* if the column is non-basic, it is integer feasible */
+         if (col->stat != GLP_BS) continue;
+         /* obtain the type and bounds of the column */
+         type = col->type, lb = col->lb, ub = col->ub;
+         /* obtain value of the column in optimal basic solution */
+         x = col->prim;
+         /* if the column's primal value is close to the lower bound,
+            the column is integer feasible within given tolerance */
+         if (type == GLP_LO || type == GLP_DB || type == GLP_FX)
+         {  temp1 = lb - T->parm->tol_int;
+            temp2 = lb + T->parm->tol_int;
+            if (temp1 <= x && x <= temp2) continue;
+#if 0
+            /* the lower bound must not be violated */
+            xassert(x >= lb);
+#else
+            if (x < lb) continue;
+#endif
+         }
+         /* if the column's primal value is close to the upper bound,
+            the column is integer feasible within given tolerance */
+         if (type == GLP_UP || type == GLP_DB || type == GLP_FX)
+         {  temp1 = ub - T->parm->tol_int;
+            temp2 = ub + T->parm->tol_int;
+            if (temp1 <= x && x <= temp2) continue;
+#if 0
+            /* the upper bound must not be violated */
+            xassert(x <= ub);
+#else
+            if (x > ub) continue;
+#endif
+         }
+         /* if the column's primal value is close to nearest integer,
+            the column is integer feasible within given tolerance */
+         temp1 = floor(x + 0.5) - T->parm->tol_int;
+         temp2 = floor(x + 0.5) + T->parm->tol_int;
+         if (temp1 <= x && x <= temp2) continue;
+         /* otherwise the column is integer infeasible */
+         T->non_int[j] = 1;
+         /* increase the number of fractional-valued columns */
+         ii_cnt++;
+         /* compute the sum of integer infeasibilities */
+         temp1 = x - floor(x);
+         temp2 = ceil(x) - x;
+         xassert(temp1 > 0.0 && temp2 > 0.0);
+         ii_sum += (temp1 <= temp2 ? temp1 : temp2);
+      }
+      /* store ii_cnt and ii_sum to the current problem descriptor */
+      xassert(T->curr != NULL);
+      T->curr->ii_cnt = ii_cnt;
+      T->curr->ii_sum = ii_sum;
+      /* and also display these parameters */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  if (ii_cnt == 0)
+            xprintf("There are no fractional columns\n");
+         else if (ii_cnt == 1)
+            xprintf("There is one fractional column, integer infeasibil"
+               "ity is %.3e\n", ii_sum);
+         else
+            xprintf("There are %d fractional columns, integer infeasibi"
+               "lity is %.3e\n", ii_cnt, ii_sum);
+      }
+      return;
+}
+
+/***********************************************************************
+*  record_solution - record better integer feasible solution
+*
+*  This routine records optimal basic solution of LP relaxation of the
+*  current subproblem, which being integer feasible is better than the
+*  best known integer feasible solution. */
+
+static void record_solution(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int i, j;
+      mip->mip_stat = GLP_FEAS;
+      mip->mip_obj = mip->obj_val;
+      for (i = 1; i <= mip->m; i++)
+      {  GLPROW *row = mip->row[i];
+         row->mipx = row->prim;
+      }
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         if (col->kind == GLP_CV)
+            col->mipx = col->prim;
+         else if (col->kind == GLP_IV)
+         {  /* value of the integer column must be integral */
+            col->mipx = floor(col->prim + 0.5);
+         }
+         else
+            xassert(col != col);
+      }
+      T->sol_cnt++;
+      return;
+}
+
+/***********************************************************************
+*  fix_by_red_cost - fix non-basic integer columns by reduced costs
+*
+*  This routine fixes some non-basic integer columns if their reduced
+*  costs indicate that increasing (decreasing) the column at least by
+*  one involves the objective value becoming worse than the incumbent
+*  objective value. */
+
+static void fix_by_red_cost(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int j, stat, fixed = 0;
+      double obj, lb, ub, dj;
+      /* the global bound must exist */
+      xassert(T->mip->mip_stat == GLP_FEAS);
+      /* basic solution of LP relaxation must be optimal */
+      xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
+      /* determine the objective function value */
+      obj = mip->obj_val;
+      /* walk through the column list */
+      for (j = 1; j <= mip->n; j++)
+      {  GLPCOL *col = mip->col[j];
+         /* if the column is not integer, skip it */
+         if (col->kind != GLP_IV) continue;
+         /* obtain bounds of j-th column */
+         lb = col->lb, ub = col->ub;
+         /* and determine its status and reduced cost */
+         stat = col->stat, dj = col->dual;
+         /* analyze the reduced cost */
+         switch (mip->dir)
+         {  case GLP_MIN:
+               /* minimization */
+               if (stat == GLP_NL)
+               {  /* j-th column is non-basic on its lower bound */
+                  if (dj < 0.0) dj = 0.0;
+                  if (obj + dj >= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
+               }
+               else if (stat == GLP_NU)
+               {  /* j-th column is non-basic on its upper bound */
+                  if (dj > 0.0) dj = 0.0;
+                  if (obj - dj >= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
+               }
+               break;
+            case GLP_MAX:
+               /* maximization */
+               if (stat == GLP_NL)
+               {  /* j-th column is non-basic on its lower bound */
+                  if (dj > 0.0) dj = 0.0;
+                  if (obj + dj <= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++;
+               }
+               else if (stat == GLP_NU)
+               {  /* j-th column is non-basic on its upper bound */
+                  if (dj < 0.0) dj = 0.0;
+                  if (obj - dj <= mip->mip_obj)
+                     glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++;
+               }
+               break;
+            default:
+               xassert(T != T);
+         }
+      }
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  if (fixed == 0)
+            /* nothing to say */;
+         else if (fixed == 1)
+            xprintf("One column has been fixed by reduced cost\n");
+         else
+            xprintf("%d columns have been fixed by reduced costs\n",
+               fixed);
+      }
+      /* fixing non-basic columns on their current bounds does not
+         change the basic solution */
+      xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS);
+      return;
+}
+
+/***********************************************************************
+*  branch_on - perform branching on specified variable
+*
+*  This routine performs branching on j-th column (structural variable)
+*  of the current subproblem. The specified column must be of integer
+*  kind and must have a fractional value in optimal basic solution of
+*  LP relaxation of the current subproblem (i.e. only columns for which
+*  the flag non_int[j] is set are valid candidates to branch on).
+*
+*  Let x be j-th structural variable, and beta be its primal fractional
+*  value in the current basic solution. Branching on j-th variable is
+*  dividing the current subproblem into two new subproblems, which are
+*  identical to the current subproblem with the following exception: in
+*  the first subproblem that begins the down-branch x has a new upper
+*  bound x <= floor(beta), and in the second subproblem that begins the
+*  up-branch x has a new lower bound x >= ceil(beta).
+*
+*  Depending on estimation of local bounds for down- and up-branches
+*  this routine returns the following:
+*
+*  0 - both branches have been created;
+*  1 - one branch is hopeless and has been pruned, so now the current
+*      subproblem is other branch;
+*  2 - both branches are hopeless and have been pruned; new subproblem
+*      selection is needed to continue the search. */
+
+static int branch_on(glp_tree *T, int j, int next)
+{     glp_prob *mip = T->mip;
+      IOSNPD *node;
+      int m = mip->m;
+      int n = mip->n;
+      int type, dn_type, up_type, dn_bad, up_bad, p, ret, clone[1+2];
+      double lb, ub, beta, new_ub, new_lb, dn_lp, up_lp, dn_bnd, up_bnd;
+      /* determine bounds and value of x[j] in optimal solution to LP
+         relaxation of the current subproblem */
+      xassert(1 <= j && j <= n);
+      type = mip->col[j]->type;
+      lb = mip->col[j]->lb;
+      ub = mip->col[j]->ub;
+      beta = mip->col[j]->prim;
+      /* determine new bounds of x[j] for down- and up-branches */
+      new_ub = floor(beta);
+      new_lb = ceil(beta);
+      switch (type)
+      {  case GLP_FR:
+            dn_type = GLP_UP;
+            up_type = GLP_LO;
+            break;
+         case GLP_LO:
+            xassert(lb <= new_ub);
+            dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
+            xassert(lb + 1.0 <= new_lb);
+            up_type = GLP_LO;
+            break;
+         case GLP_UP:
+            xassert(new_ub <= ub - 1.0);
+            dn_type = GLP_UP;
+            xassert(new_lb <= ub);
+            up_type = (new_lb == ub ? GLP_FX : GLP_DB);
+            break;
+         case GLP_DB:
+            xassert(lb <= new_ub && new_ub <= ub - 1.0);
+            dn_type = (lb == new_ub ? GLP_FX : GLP_DB);
+            xassert(lb + 1.0 <= new_lb && new_lb <= ub);
+            up_type = (new_lb == ub ? GLP_FX : GLP_DB);
+            break;
+         default:
+            xassert(type != type);
+      }
+      /* compute local bounds to LP relaxation for both branches */
+      ios_eval_degrad(T, j, &dn_lp, &up_lp);
+      /* and improve them by rounding */
+      dn_bnd = ios_round_bound(T, dn_lp);
+      up_bnd = ios_round_bound(T, up_lp);
+      /* check local bounds for down- and up-branches */
+      dn_bad = !ios_is_hopeful(T, dn_bnd);
+      up_bad = !ios_is_hopeful(T, up_bnd);
+      if (dn_bad && up_bad)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Both down- and up-branches are hopeless\n");
+         ret = 2;
+         goto done;
+      }
+      else if (up_bad)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Up-branch is hopeless\n");
+         glp_set_col_bnds(mip, j, dn_type, lb, new_ub);
+         T->curr->lp_obj = dn_lp;
+         if (mip->dir == GLP_MIN)
+         {  if (T->curr->bound < dn_bnd)
+                T->curr->bound = dn_bnd;
+         }
+         else if (mip->dir == GLP_MAX)
+         {  if (T->curr->bound > dn_bnd)
+                T->curr->bound = dn_bnd;
+         }
+         else
+            xassert(mip != mip);
+         ret = 1;
+         goto done;
+      }
+      else if (dn_bad)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Down-branch is hopeless\n");
+         glp_set_col_bnds(mip, j, up_type, new_lb, ub);
+         T->curr->lp_obj = up_lp;
+         if (mip->dir == GLP_MIN)
+         {  if (T->curr->bound < up_bnd)
+                T->curr->bound = up_bnd;
+         }
+         else if (mip->dir == GLP_MAX)
+         {  if (T->curr->bound > up_bnd)
+                T->curr->bound = up_bnd;
+         }
+         else
+            xassert(mip != mip);
+         ret = 1;
+         goto done;
+      }
+      /* both down- and up-branches seem to be hopeful */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Branching on column %d, primal value is %.9e\n",
+            j, beta);
+      /* determine the reference number of the current subproblem */
+      xassert(T->curr != NULL);
+      p = T->curr->p;
+      T->curr->br_var = j;
+      T->curr->br_val = beta;
+      /* freeze the current subproblem */
+      ios_freeze_node(T);
+      /* create two clones of the current subproblem; the first clone
+         begins the down-branch, the second one begins the up-branch */
+      ios_clone_node(T, p, 2, clone);
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Node %d begins down branch, node %d begins up branch "
+            "\n", clone[1], clone[2]);
+      /* set new upper bound of j-th column in the down-branch */
+      node = T->slot[clone[1]].node;
+      xassert(node != NULL);
+      xassert(node->up != NULL);
+      xassert(node->b_ptr == NULL);
+      node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
+      node->b_ptr->k = m + j;
+      node->b_ptr->type = (unsigned char)dn_type;
+      node->b_ptr->lb = lb;
+      node->b_ptr->ub = new_ub;
+      node->b_ptr->next = NULL;
+      node->lp_obj = dn_lp;
+      if (mip->dir == GLP_MIN)
+      {  if (node->bound < dn_bnd)
+             node->bound = dn_bnd;
+      }
+      else if (mip->dir == GLP_MAX)
+      {  if (node->bound > dn_bnd)
+             node->bound = dn_bnd;
+      }
+      else
+         xassert(mip != mip);
+      /* set new lower bound of j-th column in the up-branch */
+      node = T->slot[clone[2]].node;
+      xassert(node != NULL);
+      xassert(node->up != NULL);
+      xassert(node->b_ptr == NULL);
+      node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND));
+      node->b_ptr->k = m + j;
+      node->b_ptr->type = (unsigned char)up_type;
+      node->b_ptr->lb = new_lb;
+      node->b_ptr->ub = ub;
+      node->b_ptr->next = NULL;
+      node->lp_obj = up_lp;
+      if (mip->dir == GLP_MIN)
+      {  if (node->bound < up_bnd)
+             node->bound = up_bnd;
+      }
+      else if (mip->dir == GLP_MAX)
+      {  if (node->bound > up_bnd)
+             node->bound = up_bnd;
+      }
+      else
+         xassert(mip != mip);
+      /* suggest the subproblem to be solved next */
+      xassert(T->child == 0);
+      if (next == GLP_NO_BRNCH)
+         T->child = 0;
+      else if (next == GLP_DN_BRNCH)
+         T->child = clone[1];
+      else if (next == GLP_UP_BRNCH)
+         T->child = clone[2];
+      else
+         xassert(next != next);
+      ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+*  cleanup_the_tree - prune hopeless branches from the tree
+*
+*  This routine walks through the active list and checks the local
+*  bound for every active subproblem. If the local bound indicates that
+*  the subproblem cannot have integer optimal solution better than the
+*  incumbent objective value, the routine deletes such subproblem that,
+*  in turn, involves pruning the corresponding branch of the tree. */
+
+static void cleanup_the_tree(glp_tree *T)
+{     IOSNPD *node, *next_node;
+      int count = 0;
+      /* the global bound must exist */
+      xassert(T->mip->mip_stat == GLP_FEAS);
+      /* walk through the list of active subproblems */
+      for (node = T->head; node != NULL; node = next_node)
+      {  /* deleting some active problem node may involve deleting its
+            parents recursively; however, all its parents being created
+            *before* it are always *precede* it in the node list, so
+            the next problem node is never affected by such deletion */
+         next_node = node->next;
+         /* if the branch is hopeless, prune it */
+         if (!is_branch_hopeful(T, node->p))
+            ios_delete_node(T, node->p), count++;
+      }
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  if (count == 1)
+            xprintf("One hopeless branch has been pruned\n");
+         else if (count > 1)
+            xprintf("%d hopeless branches have been pruned\n", count);
+      }
+      return;
+}
+
+/**********************************************************************/
+
+static void generate_cuts(glp_tree *T)
+{     /* generate generic cuts with built-in generators */
+      if (!(T->parm->mir_cuts == GLP_ON ||
+            T->parm->gmi_cuts == GLP_ON ||
+            T->parm->cov_cuts == GLP_ON ||
+            T->parm->clq_cuts == GLP_ON)) goto done;
+#if 1 /* 20/IX-2008 */
+      {  int i, max_cuts, added_cuts;
+         max_cuts = T->n;
+         if (max_cuts < 1000) max_cuts = 1000;
+         added_cuts = 0;
+         for (i = T->orig_m+1; i <= T->mip->m; i++)
+         {  if (T->mip->row[i]->origin == GLP_RF_CUT)
+               added_cuts++;
+         }
+         /* xprintf("added_cuts = %d\n", added_cuts); */
+         if (added_cuts >= max_cuts) goto done;
+      }
+#endif
+      /* generate and add to POOL all cuts violated by x* */
+      if (T->parm->gmi_cuts == GLP_ON)
+      {  if (T->curr->changed < 5)
+            ios_gmi_gen(T);
+      }
+      if (T->parm->mir_cuts == GLP_ON)
+      {  xassert(T->mir_gen != NULL);
+         ios_mir_gen(T, T->mir_gen);
+      }
+      if (T->parm->cov_cuts == GLP_ON)
+      {  /* cover cuts works well along with mir cuts */
+         /*if (T->round <= 5)*/
+            ios_cov_gen(T);
+      }
+      if (T->parm->clq_cuts == GLP_ON)
+      {  if (T->clq_gen != NULL)
+         {  if (T->curr->level == 0 && T->curr->changed < 50 ||
+                T->curr->level >  0 && T->curr->changed < 5)
+               ios_clq_gen(T, T->clq_gen);
+         }
+      }
+done: return;
+}
+
+/**********************************************************************/
+
+static void remove_cuts(glp_tree *T)
+{     /* remove inactive cuts (some valueable globally valid cut might
+         be saved in the global cut pool) */
+      int i, cnt = 0, *num = NULL;
+      xassert(T->curr != NULL);
+      for (i = T->orig_m+1; i <= T->mip->m; i++)
+      {  if (T->mip->row[i]->origin == GLP_RF_CUT &&
+             T->mip->row[i]->level == T->curr->level &&
+             T->mip->row[i]->stat == GLP_BS)
+         {  if (num == NULL)
+               num = xcalloc(1+T->mip->m, sizeof(int));
+            num[++cnt] = i;
+         }
+      }
+      if (cnt > 0)
+      {  glp_del_rows(T->mip, cnt, num);
+#if 0
+         xprintf("%d inactive cut(s) removed\n", cnt);
+#endif
+         xfree(num);
+         xassert(glp_factorize(T->mip) == 0);
+      }
+      return;
+}
+
+/**********************************************************************/
+
+static void display_cut_info(glp_tree *T)
+{     glp_prob *mip = T->mip;
+      int i, gmi = 0, mir = 0, cov = 0, clq = 0, app = 0;
+      for (i = mip->m; i > 0; i--)
+      {  GLPROW *row;
+         row = mip->row[i];
+         /* if (row->level < T->curr->level) break; */
+         if (row->origin == GLP_RF_CUT)
+         {  if (row->klass == GLP_RF_GMI)
+               gmi++;
+            else if (row->klass == GLP_RF_MIR)
+               mir++;
+            else if (row->klass == GLP_RF_COV)
+               cov++;
+            else if (row->klass == GLP_RF_CLQ)
+               clq++;
+            else
+               app++;
+         }
+      }
+      xassert(T->curr != NULL);
+      if (gmi + mir + cov + clq + app > 0)
+      {  xprintf("Cuts on level %d:", T->curr->level);
+         if (gmi > 0) xprintf(" gmi = %d;", gmi);
+         if (mir > 0) xprintf(" mir = %d;", mir);
+         if (cov > 0) xprintf(" cov = %d;", cov);
+         if (clq > 0) xprintf(" clq = %d;", clq);
+         if (app > 0) xprintf(" app = %d;", app);
+         xprintf("\n");
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_driver - branch-and-cut driver
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_driver(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_driver is a branch-and-cut driver. It controls the
+*  MIP solution process.
+*
+*  RETURNS
+*
+*  0  The MIP problem instance has been successfully solved. This code
+*     does not necessarily mean that the solver has found optimal
+*     solution. It only means that the solution process was successful.
+*
+*  GLP_EFAIL
+*     The search was prematurely terminated due to the solver failure.
+*
+*  GLP_EMIPGAP
+*     The search was prematurely terminated, because the relative mip
+*     gap tolerance has been reached.
+*
+*  GLP_ETMLIM
+*     The search was prematurely terminated, because the time limit has
+*     been exceeded.
+*
+*  GLP_ESTOP
+*     The search was prematurely terminated by application. */
+
+int ios_driver(glp_tree *T)
+{     int p, curr_p, p_stat, d_stat, ret;
+#if 1 /* carry out to glp_tree */
+      int pred_p = 0;
+      /* if the current subproblem has been just created due to
+         branching, pred_p is the reference number of its parent
+         subproblem, otherwise pred_p is zero */
+#endif
+      glp_long ttt = T->tm_beg;
+#if 0
+      ((glp_iocp *)T->parm)->msg_lev = GLP_MSG_DBG;
+#endif
+      /* on entry to the B&B driver it is assumed that the active list
+         contains the only active (i.e. root) subproblem, which is the
+         original MIP problem to be solved */
+loop: /* main loop starts here */
+      /* at this point the current subproblem does not exist */
+      xassert(T->curr == NULL);
+      /* if the active list is empty, the search is finished */
+      if (T->head == NULL)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Active list is empty!\n");
+         xassert(dmp_in_use(T->pool).lo == 0);
+         ret = 0;
+         goto done;
+      }
+      /* select some active subproblem to continue the search */
+      xassert(T->next_p == 0);
+      /* let the application program select subproblem */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ISELECT;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      if (T->next_p != 0)
+      {  /* the application program has selected something */
+         ;
+      }
+      else if (T->a_cnt == 1)
+      {  /* the only active subproblem exists, so select it */
+         xassert(T->head->next == NULL);
+         T->next_p = T->head->p;
+      }
+      else if (T->child != 0)
+      {  /* select one of branching childs suggested by the branching
+            heuristic */
+         T->next_p = T->child;
+      }
+      else
+      {  /* select active subproblem as specified by the backtracking
+            technique option */
+         T->next_p = ios_choose_node(T);
+      }
+      /* the active subproblem just selected becomes current */
+      ios_revive_node(T, T->next_p);
+      T->next_p = T->child = 0;
+      /* invalidate pred_p, if it is not the reference number of the
+         parent of the current subproblem */
+      if (T->curr->up != NULL && T->curr->up->p != pred_p) pred_p = 0;
+      /* determine the reference number of the current subproblem */
+      p = T->curr->p;
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  xprintf("-----------------------------------------------------"
+            "-------------------\n");
+         xprintf("Processing node %d at level %d\n", p, T->curr->level);
+      }
+      /* if it is the root subproblem, initialize cut generators */
+      if (p == 1)
+      {  if (T->parm->gmi_cuts == GLP_ON)
+         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("Gomory's cuts enabled\n");
+         }
+         if (T->parm->mir_cuts == GLP_ON)
+         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("MIR cuts enabled\n");
+            xassert(T->mir_gen == NULL);
+            T->mir_gen = ios_mir_init(T);
+         }
+         if (T->parm->cov_cuts == GLP_ON)
+         {  if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("Cover cuts enabled\n");
+         }
+         if (T->parm->clq_cuts == GLP_ON)
+         {  xassert(T->clq_gen == NULL);
+            if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("Clique cuts enabled\n");
+            T->clq_gen = ios_clq_init(T);
+         }
+      }
+more: /* minor loop starts here */
+      /* at this point the current subproblem needs either to be solved
+         for the first time or re-optimized due to reformulation */
+      /* display current progress of the search */
+      if (T->parm->msg_lev >= GLP_MSG_DBG ||
+          T->parm->msg_lev >= GLP_MSG_ON &&
+        (double)(T->parm->out_frq - 1) <=
+            1000.0 * xdifftime(xtime(), T->tm_lag))
+         show_progress(T, 0);
+      if (T->parm->msg_lev >= GLP_MSG_ALL &&
+            xdifftime(xtime(), ttt) >= 60.0)
+      {  glp_long total;
+         glp_mem_usage(NULL, NULL, &total, NULL);
+         xprintf("Time used: %.1f secs.  Memory used: %.1f Mb.\n",
+            xdifftime(xtime(), T->tm_beg), xltod(total) / 1048576.0);
+         ttt = xtime();
+      }
+      /* check the mip gap */
+      if (T->parm->mip_gap > 0.0 &&
+          ios_relative_gap(T) <= T->parm->mip_gap)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Relative gap tolerance reached; search terminated "
+               "\n");
+         ret = GLP_EMIPGAP;
+         goto done;
+      }
+      /* check if the time limit has been exhausted */
+      if (T->parm->tm_lim < INT_MAX &&
+         (double)(T->parm->tm_lim - 1) <=
+         1000.0 * xdifftime(xtime(), T->tm_beg))
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Time limit exhausted; search terminated\n");
+         ret = GLP_ETMLIM;
+         goto done;
+      }
+      /* let the application program preprocess the subproblem */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IPREPRO;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      /* perform basic preprocessing */
+      if (T->parm->pp_tech == GLP_PP_NONE)
+         ;
+      else if (T->parm->pp_tech == GLP_PP_ROOT)
+      {  if (T->curr->level == 0)
+         {  if (ios_preprocess_node(T, 100))
+               goto fath;
+         }
+      }
+      else if (T->parm->pp_tech == GLP_PP_ALL)
+      {  if (ios_preprocess_node(T, T->curr->level == 0 ? 100 : 10))
+            goto fath;
+      }
+      else
+         xassert(T != T);
+      /* preprocessing may improve the global bound */
+      if (!is_branch_hopeful(T, p))
+      {  xprintf("*** not tested yet ***\n");
+         goto fath;
+      }
+      /* solve LP relaxation of the current subproblem */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Solving LP relaxation...\n");
+      ret = ios_solve_node(T);
+      if (!(ret == 0 || ret == GLP_EOBJLL || ret == GLP_EOBJUL))
+      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("ios_driver: unable to solve current LP relaxation;"
+               " glp_simplex returned %d\n", ret);
+         ret = GLP_EFAIL;
+         goto done;
+      }
+      /* analyze status of the basic solution to LP relaxation found */
+      p_stat = T->mip->pbs_stat;
+      d_stat = T->mip->dbs_stat;
+      if (p_stat == GLP_FEAS && d_stat == GLP_FEAS)
+      {  /* LP relaxation has optimal solution */
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Found optimal solution to LP relaxation\n");
+      }
+      else if (d_stat == GLP_NOFEAS)
+      {  /* LP relaxation has no dual feasible solution */
+         /* since the current subproblem cannot have a larger feasible
+            region than its parent, there is something wrong */
+         if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("ios_driver: current LP relaxation has no dual feas"
+               "ible solution\n");
+         ret = GLP_EFAIL;
+         goto done;
+      }
+      else if (p_stat == GLP_INFEAS && d_stat == GLP_FEAS)
+      {  /* LP relaxation has no primal solution which is better than
+            the incumbent objective value */
+         xassert(T->mip->mip_stat == GLP_FEAS);
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("LP relaxation has no solution better than incumben"
+               "t objective value\n");
+         /* prune the branch */
+         goto fath;
+      }
+      else if (p_stat == GLP_NOFEAS)
+      {  /* LP relaxation has no primal feasible solution */
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("LP relaxation has no feasible solution\n");
+         /* prune the branch */
+         goto fath;
+      }
+      else
+      {  /* other cases cannot appear */
+         xassert(T->mip != T->mip);
+      }
+      /* at this point basic solution to LP relaxation of the current
+         subproblem is optimal */
+      xassert(p_stat == GLP_FEAS && d_stat == GLP_FEAS);
+      xassert(T->curr != NULL);
+      T->curr->lp_obj = T->mip->obj_val;
+      /* thus, it defines a local bound to integer optimal solution of
+         the current subproblem */
+      {  double bound = T->mip->obj_val;
+         /* some local bound to the current subproblem could be already
+            set before, so we should only improve it */
+         bound = ios_round_bound(T, bound);
+         if (T->mip->dir == GLP_MIN)
+         {  if (T->curr->bound < bound)
+               T->curr->bound = bound;
+         }
+         else if (T->mip->dir == GLP_MAX)
+         {  if (T->curr->bound > bound)
+               T->curr->bound = bound;
+         }
+         else
+            xassert(T->mip != T->mip);
+         if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Local bound is %.9e\n", bound);
+      }
+      /* if the local bound indicates that integer optimal solution of
+         the current subproblem cannot be better than the global bound,
+         prune the branch */
+      if (!is_branch_hopeful(T, p))
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("Current branch is hopeless and can be pruned\n");
+         goto fath;
+      }
+      /* let the application program generate additional rows ("lazy"
+         constraints) */
+      xassert(T->reopt == 0);
+      xassert(T->reinv == 0);
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IROWGEN;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+         if (T->reopt)
+         {  /* some rows were added; re-optimization is needed */
+            T->reopt = T->reinv = 0;
+            goto more;
+         }
+         if (T->reinv)
+         {  /* no rows were added, however, some inactive rows were
+               removed */
+            T->reinv = 0;
+            xassert(glp_factorize(T->mip) == 0);
+         }
+      }
+      /* check if the basic solution is integer feasible */
+      check_integrality(T);
+      /* if the basic solution satisfies to all integrality conditions,
+         it is a new, better integer feasible solution */
+      if (T->curr->ii_cnt == 0)
+      {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+            xprintf("New integer feasible solution found\n");
+         if (T->parm->msg_lev >= GLP_MSG_ALL)
+            display_cut_info(T);
+         record_solution(T);
+         if (T->parm->msg_lev >= GLP_MSG_ON)
+            show_progress(T, 1);
+         /* make the application program happy */
+         if (T->parm->cb_func != NULL)
+         {  xassert(T->reason == 0);
+            T->reason = GLP_IBINGO;
+            T->parm->cb_func(T, T->parm->cb_info);
+            T->reason = 0;
+            if (T->stop)
+            {  ret = GLP_ESTOP;
+               goto done;
+            }
+         }
+         /* since the current subproblem has been fathomed, prune its
+            branch */
+         goto fath;
+      }
+      /* at this point basic solution to LP relaxation of the current
+         subproblem is optimal, but integer infeasible */
+      /* try to fix some non-basic structural variables of integer kind
+         on their current bounds due to reduced costs */
+      if (T->mip->mip_stat == GLP_FEAS)
+         fix_by_red_cost(T);
+      /* let the application program try to find some solution to the
+         original MIP with a primal heuristic */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IHEUR;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+         /* check if the current branch became hopeless */
+         if (!is_branch_hopeful(T, p))
+         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("Current branch became hopeless and can be prune"
+                  "d\n");
+            goto fath;
+         }
+      }
+      /* try to find solution with the feasibility pump heuristic */
+      if (T->parm->fp_heur)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_IHEUR;
+         ios_feas_pump(T);
+         T->reason = 0;
+         /* check if the current branch became hopeless */
+         if (!is_branch_hopeful(T, p))
+         {  if (T->parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("Current branch became hopeless and can be prune"
+                  "d\n");
+            goto fath;
+         }
+      }
+      /* it's time to generate cutting planes */
+      xassert(T->local != NULL);
+      xassert(T->local->size == 0);
+      /* let the application program generate some cuts; note that it
+         can add cuts either to the local cut pool or directly to the
+         current subproblem */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ICUTGEN;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      /* try to generate generic cuts with built-in generators
+         (as suggested by Matteo Fischetti et al. the built-in cuts
+         are not generated at each branching node; an intense attempt
+         of generating new cuts is only made at the root node, and then
+         a moderate effort is spent after each backtracking step) */
+      if (T->curr->level == 0 || pred_p == 0)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ICUTGEN;
+         generate_cuts(T);
+         T->reason = 0;
+      }
+      /* if the local cut pool is not empty, select useful cuts and add
+         them to the current subproblem */
+      if (T->local->size > 0)
+      {  xassert(T->reason == 0);
+         T->reason = GLP_ICUTGEN;
+         ios_process_cuts(T);
+         T->reason = 0;
+      }
+      /* clear the local cut pool */
+      ios_clear_pool(T, T->local);
+      /* perform re-optimization, if necessary */
+      if (T->reopt)
+      {  T->reopt = 0;
+         T->curr->changed++;
+         goto more;
+      }
+      /* no cuts were generated; remove inactive cuts */
+      remove_cuts(T);
+      if (T->parm->msg_lev >= GLP_MSG_ALL && T->curr->level == 0)
+         display_cut_info(T);
+      /* update history information used on pseudocost branching */
+      if (T->pcost != NULL) ios_pcost_update(T);
+      /* it's time to perform branching */
+      xassert(T->br_var == 0);
+      xassert(T->br_sel == 0);
+      /* let the application program choose variable to branch on */
+      if (T->parm->cb_func != NULL)
+      {  xassert(T->reason == 0);
+         xassert(T->br_var == 0);
+         xassert(T->br_sel == 0);
+         T->reason = GLP_IBRANCH;
+         T->parm->cb_func(T, T->parm->cb_info);
+         T->reason = 0;
+         if (T->stop)
+         {  ret = GLP_ESTOP;
+            goto done;
+         }
+      }
+      /* if nothing has been chosen, choose some variable as specified
+         by the branching technique option */
+      if (T->br_var == 0)
+         T->br_var = ios_choose_var(T, &T->br_sel);
+      /* perform actual branching */
+      curr_p = T->curr->p;
+      ret = branch_on(T, T->br_var, T->br_sel);
+      T->br_var = T->br_sel = 0;
+      if (ret == 0)
+      {  /* both branches have been created */
+         pred_p = curr_p;
+         goto loop;
+      }
+      else if (ret == 1)
+      {  /* one branch is hopeless and has been pruned, so now the
+            current subproblem is other branch */
+         /* the current subproblem should be considered as a new one,
+            since one bound of the branching variable was changed */
+         T->curr->solved = T->curr->changed = 0;
+         goto more;
+      }
+      else if (ret == 2)
+      {  /* both branches are hopeless and have been pruned; new
+            subproblem selection is needed to continue the search */
+         goto fath;
+      }
+      else
+         xassert(ret != ret);
+fath: /* the current subproblem has been fathomed */
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Node %d fathomed\n", p);
+      /* freeze the current subproblem */
+      ios_freeze_node(T);
+      /* and prune the corresponding branch of the tree */
+      ios_delete_node(T, p);
+      /* if a new integer feasible solution has just been found, other
+         branches may become hopeless and therefore must be pruned */
+      if (T->mip->mip_stat == GLP_FEAS) cleanup_the_tree(T);
+      /* new subproblem selection is needed due to backtracking */
+      pred_p = 0;
+      goto loop;
+done: /* display progress of the search on exit from the solver */
+      if (T->parm->msg_lev >= GLP_MSG_ON)
+         show_progress(T, 0);
+      if (T->mir_gen != NULL)
+         ios_mir_term(T->mir_gen), T->mir_gen = NULL;
+      if (T->clq_gen != NULL)
+         ios_clq_term(T->clq_gen), T->clq_gen = NULL;
+      /* return to the calling program */
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpios04.c
===================================================================
--- deps/glpk/src/glpios04.c	(revision 9)
+++ deps/glpk/src/glpios04.c	(revision 9)
@@ -0,0 +1,303 @@
+/* glpios04.c (operations on sparse vectors) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_create_vec - create sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  IOSVEC *ios_create_vec(int n);
+*
+*  DESCRIPTION
+*
+*  The routine ios_create_vec creates a sparse vector of dimension n,
+*  which initially is a null vector.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the vector created. */
+
+IOSVEC *ios_create_vec(int n)
+{     IOSVEC *v;
+      xassert(n >= 0);
+      v = xmalloc(sizeof(IOSVEC));
+      v->n = n;
+      v->nnz = 0;
+      v->pos = xcalloc(1+n, sizeof(int));
+      memset(&v->pos[1], 0, n * sizeof(int));
+      v->ind = xcalloc(1+n, sizeof(int));
+      v->val = xcalloc(1+n, sizeof(double));
+      return v;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_check_vec - check that sparse vector has correct representation
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_check_vec(IOSVEC *v);
+*
+*  DESCRIPTION
+*
+*  The routine ios_check_vec checks that a sparse vector specified by
+*  the parameter v has correct representation.
+*
+*  NOTE
+*
+*  Complexity of this operation is O(n). */
+
+void ios_check_vec(IOSVEC *v)
+{     int j, k, nnz;
+      xassert(v->n >= 0);
+      nnz = 0;
+      for (j = v->n; j >= 1; j--)
+      {  k = v->pos[j];
+         xassert(0 <= k && k <= v->nnz);
+         if (k != 0)
+         {  xassert(v->ind[k] == j);
+            nnz++;
+         }
+      }
+      xassert(v->nnz == nnz);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_get_vj - retrieve component of sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  double ios_get_vj(IOSVEC *v, int j);
+*
+*  RETURNS
+*
+*  The routine ios_get_vj returns j-th component of a sparse vector
+*  specified by the parameter v. */
+
+double ios_get_vj(IOSVEC *v, int j)
+{     int k;
+      xassert(1 <= j && j <= v->n);
+      k = v->pos[j];
+      xassert(0 <= k && k <= v->nnz);
+      return (k == 0 ? 0.0 : v->val[k]);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_set_vj - set/change component of sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_set_vj(IOSVEC *v, int j, double val);
+*
+*  DESCRIPTION
+*
+*  The routine ios_set_vj assigns val to j-th component of a sparse
+*  vector specified by the parameter v. */
+
+void ios_set_vj(IOSVEC *v, int j, double val)
+{     int k;
+      xassert(1 <= j && j <= v->n);
+      k = v->pos[j];
+      if (val == 0.0)
+      {  if (k != 0)
+         {  /* remove j-th component */
+            v->pos[j] = 0;
+            if (k < v->nnz)
+            {  v->pos[v->ind[v->nnz]] = k;
+               v->ind[k] = v->ind[v->nnz];
+               v->val[k] = v->val[v->nnz];
+            }
+            v->nnz--;
+         }
+      }
+      else
+      {  if (k == 0)
+         {  /* create j-th component */
+            k = ++(v->nnz);
+            v->pos[j] = k;
+            v->ind[k] = j;
+         }
+         v->val[k] = val;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clear_vec - set all components of sparse vector to zero
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clear_vec(IOSVEC *v);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clear_vec sets all components of a sparse vector
+*  specified by the parameter v to zero. */
+
+void ios_clear_vec(IOSVEC *v)
+{     int k;
+      for (k = 1; k <= v->nnz; k++)
+         v->pos[v->ind[k]] = 0;
+      v->nnz = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clean_vec - remove zero or small components from sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clean_vec(IOSVEC *v, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clean_vec removes zero components and components
+*  whose magnitude is less than eps from a sparse vector specified by
+*  the parameter v. If eps is 0.0, only zero components are removed. */
+
+void ios_clean_vec(IOSVEC *v, double eps)
+{     int k, nnz;
+      nnz = 0;
+      for (k = 1; k <= v->nnz; k++)
+      {  if (fabs(v->val[k]) == 0.0 || fabs(v->val[k]) < eps)
+         {  /* remove component */
+            v->pos[v->ind[k]] = 0;
+         }
+         else
+         {  /* keep component */
+            nnz++;
+            v->pos[v->ind[k]] = nnz;
+            v->ind[nnz] = v->ind[k];
+            v->val[nnz] = v->val[k];
+         }
+      }
+      v->nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_copy_vec - copy sparse vector (x := y)
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_copy_vec(IOSVEC *x, IOSVEC *y);
+*
+*  DESCRIPTION
+*
+*  The routine ios_copy_vec copies a sparse vector specified by the
+*  parameter y to a sparse vector specified by the parameter x. */
+
+void ios_copy_vec(IOSVEC *x, IOSVEC *y)
+{     int j;
+      xassert(x != y);
+      xassert(x->n == y->n);
+      ios_clear_vec(x);
+      x->nnz = y->nnz;
+      memcpy(&x->ind[1], &y->ind[1], x->nnz * sizeof(int));
+      memcpy(&x->val[1], &y->val[1], x->nnz * sizeof(double));
+      for (j = 1; j <= x->nnz; j++)
+         x->pos[x->ind[j]] = j;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_linear_comb - compute linear combination (x := x + a * y)
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y);
+*
+*  DESCRIPTION
+*
+*  The routine ios_linear_comb computes the linear combination
+*
+*     x := x + a * y,
+*
+*  where x and y are sparse vectors, a is a scalar. */
+
+void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y)
+{     int j, k;
+      double xj, yj;
+      xassert(x != y);
+      xassert(x->n == y->n);
+      for (k = 1; k <= y->nnz; k++)
+      {  j = y->ind[k];
+         xj = ios_get_vj(x, j);
+         yj = y->val[k];
+         ios_set_vj(x, j, xj + a * yj);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_delete_vec - delete sparse vector
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_delete_vec(IOSVEC *v);
+*
+*  DESCRIPTION
+*
+*  The routine ios_delete_vec deletes a sparse vector specified by the
+*  parameter v freeing all the memory allocated to this object. */
+
+void ios_delete_vec(IOSVEC *v)
+{     /* delete sparse vector */
+      xfree(v->pos);
+      xfree(v->ind);
+      xfree(v->val);
+      xfree(v);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpios05.c
===================================================================
--- deps/glpk/src/glpios05.c	(revision 9)
+++ deps/glpk/src/glpios05.c	(revision 9)
@@ -0,0 +1,281 @@
+/* glpios05.c (Gomory's mixed integer cut generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_gmi_gen - generate Gomory's mixed integer cuts.
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_gmi_gen(glp_tree *tree, IOSPOOL *pool);
+*
+*  DESCRIPTION
+*
+*  The routine ios_gmi_gen generates Gomory's mixed integer cuts for
+*  the current point and adds them to the cut pool. */
+
+#define MAXCUTS 50
+/* maximal number of cuts to be generated for one round */
+
+struct worka
+{     /* Gomory's cut generator working area */
+      int *ind; /* int ind[1+n]; */
+      double *val; /* double val[1+n]; */
+      double *phi; /* double phi[1+m+n]; */
+};
+
+#define f(x) ((x) - floor(x))
+/* compute fractional part of x */
+
+static void gen_cut(glp_tree *tree, struct worka *worka, int j)
+{     /* this routine tries to generate Gomory's mixed integer cut for
+         specified structural variable x[m+j] of integer kind, which is
+         basic and has fractional value in optimal solution to current
+         LP relaxation */
+      glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      int *ind = worka->ind;
+      double *val = worka->val;
+      double *phi = worka->phi;
+      int i, k, len, kind, stat;
+      double lb, ub, alfa, beta, ksi, phi1, rhs;
+      /* compute row of the simplex tableau, which (row) corresponds
+         to specified basic variable xB[i] = x[m+j]; see (23) */
+      len = glp_eval_tab_row(mip, m+j, ind, val);
+      /* determine beta[i], which a value of xB[i] in optimal solution
+         to current LP relaxation; note that this value is the same as
+         if it would be computed with formula (27); it is assumed that
+         beta[i] is fractional enough */
+      beta = mip->col[j]->prim;
+      /* compute cut coefficients phi and right-hand side rho, which
+         correspond to formula (30); dense format is used, because rows
+         of the simplex tableau is usually dense */
+      for (k = 1; k <= m+n; k++) phi[k] = 0.0;
+      rhs = f(beta); /* initial value of rho; see (28), (32) */
+      for (j = 1; j <= len; j++)
+      {  /* determine original number of non-basic variable xN[j] */
+         k = ind[j];
+         xassert(1 <= k && k <= m+n);
+         /* determine the kind, bounds and current status of xN[j] in
+            optimal solution to LP relaxation */
+         if (k <= m)
+         {  /* auxiliary variable */
+            GLPROW *row = mip->row[k];
+            kind = GLP_CV;
+            lb = row->lb;
+            ub = row->ub;
+            stat = row->stat;
+         }
+         else
+         {  /* structural variable */
+            GLPCOL *col = mip->col[k-m];
+            kind = col->kind;
+            lb = col->lb;
+            ub = col->ub;
+            stat = col->stat;
+         }
+         /* xN[j] cannot be basic */
+         xassert(stat != GLP_BS);
+         /* determine row coefficient ksi[i,j] at xN[j]; see (23) */
+         ksi = val[j];
+         /* if ksi[i,j] is too large in the magnitude, do not generate
+            the cut */
+         if (fabs(ksi) > 1e+05) goto fini;
+         /* if ksi[i,j] is too small in the magnitude, skip it */
+         if (fabs(ksi) < 1e-10) goto skip;
+         /* compute row coefficient alfa[i,j] at y[j]; see (26) */
+         switch (stat)
+         {  case GLP_NF:
+               /* xN[j] is free (unbounded) having non-zero ksi[i,j];
+                  do not generate the cut */
+               goto fini;
+            case GLP_NL:
+               /* xN[j] has active lower bound */
+               alfa = - ksi;
+               break;
+            case GLP_NU:
+               /* xN[j] has active upper bound */
+               alfa = + ksi;
+               break;
+            case GLP_NS:
+               /* xN[j] is fixed; skip it */
+               goto skip;
+            default:
+               xassert(stat != stat);
+         }
+         /* compute cut coefficient phi'[j] at y[j]; see (21), (28) */
+         switch (kind)
+         {  case GLP_IV:
+               /* y[j] is integer */
+               if (fabs(alfa - floor(alfa + 0.5)) < 1e-10)
+               {  /* alfa[i,j] is close to nearest integer; skip it */
+                  goto skip;
+               }
+               else if (f(alfa) <= f(beta))
+                  phi1 = f(alfa);
+               else
+                  phi1 = (f(beta) / (1.0 - f(beta))) * (1.0 - f(alfa));
+               break;
+            case GLP_CV:
+               /* y[j] is continuous */
+               if (alfa >= 0.0)
+                  phi1 = + alfa;
+               else
+                  phi1 = (f(beta) / (1.0 - f(beta))) * (- alfa);
+               break;
+            default:
+               xassert(kind != kind);
+         }
+         /* compute cut coefficient phi[j] at xN[j] and update right-
+            hand side rho; see (31), (32) */
+         switch (stat)
+         {  case GLP_NL:
+               /* xN[j] has active lower bound */
+               phi[k] = + phi1;
+               rhs += phi1 * lb;
+               break;
+            case GLP_NU:
+               /* xN[j] has active upper bound */
+               phi[k] = - phi1;
+               rhs -= phi1 * ub;
+               break;
+            default:
+               xassert(stat != stat);
+         }
+skip:    ;
+      }
+      /* now the cut has the form sum_k phi[k] * x[k] >= rho, where cut
+         coefficients are stored in the array phi in dense format;
+         x[1,...,m] are auxiliary variables, x[m+1,...,m+n] are struc-
+         tural variables; see (30) */
+      /* eliminate auxiliary variables in order to express the cut only
+         through structural variables; see (33) */
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row;
+         GLPAIJ *aij;
+         if (fabs(phi[i]) < 1e-10) continue;
+         /* auxiliary variable x[i] has non-zero cut coefficient */
+         row = mip->row[i];
+         /* x[i] cannot be fixed */
+         xassert(row->type != GLP_FX);
+         /* substitute x[i] = sum_j a[i,j] * x[m+j] */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            phi[m+aij->col->j] += phi[i] * aij->val;
+      }
+      /* convert the final cut to sparse format and substitute fixed
+         (structural) variables */
+      len = 0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col;
+         if (fabs(phi[m+j]) < 1e-10) continue;
+         /* structural variable x[m+j] has non-zero cut coefficient */
+         col = mip->col[j];
+         if (col->type == GLP_FX)
+         {  /* eliminate x[m+j] */
+            rhs -= phi[m+j] * col->lb;
+         }
+         else
+         {  len++;
+            ind[len] = j;
+            val[len] = phi[m+j];
+         }
+      }
+      if (fabs(rhs) < 1e-12) rhs = 0.0;
+      /* if the cut inequality seems to be badly scaled, reject it to
+         avoid numeric difficulties */
+      for (k = 1; k <= len; k++)
+      {  if (fabs(val[k]) < 1e-03) goto fini;
+         if (fabs(val[k]) > 1e+03) goto fini;
+      }
+      /* add the cut to the cut pool for further consideration */
+#if 0
+      ios_add_cut_row(tree, pool, GLP_RF_GMI, len, ind, val, GLP_LO,
+         rhs);
+#else
+      glp_ios_add_row(tree, NULL, GLP_RF_GMI, 0, len, ind, val, GLP_LO,
+         rhs);
+#endif
+fini: return;
+}
+
+struct var { int j; double f; };
+
+static int fcmp(const void *p1, const void *p2)
+{     const struct var *v1 = p1, *v2 = p2;
+      if (v1->f > v2->f) return -1;
+      if (v1->f < v2->f) return +1;
+      return 0;
+}
+
+void ios_gmi_gen(glp_tree *tree)
+{     /* main routine to generate Gomory's cuts */
+      glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      struct var *var;
+      int k, nv, j, size;
+      struct worka _worka, *worka = &_worka;
+      /* allocate working arrays */
+      var = xcalloc(1+n, sizeof(struct var));
+      worka->ind = xcalloc(1+n, sizeof(int));
+      worka->val = xcalloc(1+n, sizeof(double));
+      worka->phi = xcalloc(1+m+n, sizeof(double));
+      /* build the list of integer structural variables, which are
+         basic and have fractional value in optimal solution to current
+         LP relaxation */
+      nv = 0;
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = mip->col[j];
+         double frac;
+         if (col->kind != GLP_IV) continue;
+         if (col->type == GLP_FX) continue;
+         if (col->stat != GLP_BS) continue;
+         frac = f(col->prim);
+         if (!(0.05 <= frac && frac <= 0.95)) continue;
+         /* add variable to the list */
+         nv++, var[nv].j = j, var[nv].f = frac;
+      }
+      /* order the list by descending fractionality */
+      qsort(&var[1], nv, sizeof(struct var), fcmp);
+      /* try to generate cuts by one for each variable in the list, but
+         not more than MAXCUTS cuts */
+      size = glp_ios_pool_size(tree);
+      for (k = 1; k <= nv; k++)
+      {  if (glp_ios_pool_size(tree) - size >= MAXCUTS) break;
+         gen_cut(tree, worka, var[k].j);
+      }
+      /* free working arrays */
+      xfree(var);
+      xfree(worka->ind);
+      xfree(worka->val);
+      xfree(worka->phi);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpios06.c
===================================================================
--- deps/glpk/src/glpios06.c	(revision 9)
+++ deps/glpk/src/glpios06.c	(revision 9)
@@ -0,0 +1,1447 @@
+/* glpios06.c (MIR cut generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+#define _MIR_DEBUG 0
+
+#define MAXAGGR 5
+/* maximal number of rows which can be aggregated */
+
+struct MIR
+{     /* MIR cut generator working area */
+      /*--------------------------------------------------------------*/
+      /* global information valid for the root subproblem */
+      int m;
+      /* number of rows (in the root subproblem) */
+      int n;
+      /* number of columns */
+      char *skip; /* char skip[1+m]; */
+      /* skip[i], 1 <= i <= m, is a flag that means that row i should
+         not be used because (1) it is not suitable, or (2) because it
+         has been used in the aggregated constraint */
+      char *isint; /* char isint[1+m+n]; */
+      /* isint[k], 1 <= k <= m+n, is a flag that means that variable
+         x[k] is integer (otherwise, continuous) */
+      double *lb; /* double lb[1+m+n]; */
+      /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means
+         that x[k] has no lower bound */
+      int *vlb; /* int vlb[1+m+n]; */
+      /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable,
+         which defines variable lower bound x[k] >= lb[k] * x[k']; zero
+         means that x[k] has simple lower bound */
+      double *ub; /* double ub[1+m+n]; */
+      /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means
+         that x[k] has no upper bound */
+      int *vub; /* int vub[1+m+n]; */
+      /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable,
+         which defines variable upper bound x[k] <= ub[k] * x[k']; zero
+         means that x[k] has simple upper bound */
+      /*--------------------------------------------------------------*/
+      /* current (fractional) point to be separated */
+      double *x; /* double x[1+m+n]; */
+      /* x[k] is current value of auxiliary (1 <= k <= m) or structural
+         (m+1 <= k <= m+n) variable */
+      /*--------------------------------------------------------------*/
+      /* aggregated constraint sum a[k] * x[k] = b, which is a linear
+         combination of original constraints transformed to equalities
+         by introducing auxiliary variables */
+      int agg_cnt;
+      /* number of rows (original constraints) used to build aggregated
+         constraint, 1 <= agg_cnt <= MAXAGGR */
+      int *agg_row; /* int agg_row[1+MAXAGGR]; */
+      /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build
+         aggregated constraint */
+      IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */
+      /* sparse vector of aggregated constraint coefficients, a[k] */
+      double agg_rhs;
+      /* right-hand side of the aggregated constraint, b */
+      /*--------------------------------------------------------------*/
+      /* bound substitution flags for modified constraint */
+      char *subst; /* char subst[1+m+n]; */
+      /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for
+         variable x[k]:
+         '?' - x[k] is missing in modified constraint
+         'L' - x[k] = (lower bound) + x'[k]
+         'U' - x[k] = (upper bound) - x'[k] */
+      /*--------------------------------------------------------------*/
+      /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0,
+         derived from aggregated constraint by substituting bounds;
+         note that due to substitution of variable bounds there may be
+         additional terms in the modified constraint */
+      IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */
+      /* sparse vector of modified constraint coefficients, a'[k] */
+      double mod_rhs;
+      /* right-hand side of the modified constraint, b' */
+      /*--------------------------------------------------------------*/
+      /* cutting plane sum alpha[k] * x[k] <= beta */
+      IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */
+      /* sparse vector of cutting plane coefficients, alpha[k] */
+      double cut_rhs;
+      /* right-hand size of the cutting plane, beta */
+};
+
+/***********************************************************************
+*  NAME
+*
+*  ios_mir_init - initialize MIR cut generator
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void *ios_mir_init(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_mir_init initializes the MIR cut generator assuming
+*  that the current subproblem is the root subproblem.
+*
+*  RETURNS
+*
+*  The routine ios_mir_init returns a pointer to the MIR cut generator
+*  working area. */
+
+static void set_row_attrib(glp_tree *tree, struct MIR *mir)
+{     /* set global row attributes */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int k;
+      for (k = 1; k <= m; k++)
+      {  GLPROW *row = mip->row[k];
+         mir->skip[k] = 0;
+         mir->isint[k] = 0;
+         switch (row->type)
+         {  case GLP_FR:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
+            case GLP_LO:
+               mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break;
+            case GLP_UP:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break;
+            case GLP_DB:
+               mir->lb[k] = row->lb, mir->ub[k] = row->ub; break;
+            case GLP_FX:
+               mir->lb[k] = mir->ub[k] = row->lb; break;
+            default:
+               xassert(row != row);
+         }
+         mir->vlb[k] = mir->vub[k] = 0;
+      }
+      return;
+}
+
+static void set_col_attrib(glp_tree *tree, struct MIR *mir)
+{     /* set global column attributes */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      int k;
+      for (k = m+1; k <= m+n; k++)
+      {  GLPCOL *col = mip->col[k-m];
+         switch (col->kind)
+         {  case GLP_CV:
+               mir->isint[k] = 0; break;
+            case GLP_IV:
+               mir->isint[k] = 1; break;
+            default:
+               xassert(col != col);
+         }
+         switch (col->type)
+         {  case GLP_FR:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break;
+            case GLP_LO:
+               mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break;
+            case GLP_UP:
+               mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break;
+            case GLP_DB:
+               mir->lb[k] = col->lb, mir->ub[k] = col->ub; break;
+            case GLP_FX:
+               mir->lb[k] = mir->ub[k] = col->lb; break;
+            default:
+               xassert(col != col);
+         }
+         mir->vlb[k] = mir->vub[k] = 0;
+      }
+      return;
+}
+
+static void set_var_bounds(glp_tree *tree, struct MIR *mir)
+{     /* set variable bounds */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      GLPAIJ *aij;
+      int i, k1, k2;
+      double a1, a2;
+      for (i = 1; i <= m; i++)
+      {  /* we need the row to be '>= 0' or '<= 0' */
+         if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX ||
+               mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue;
+         /* take first term */
+         aij = mip->row[i]->ptr;
+         if (aij == NULL) continue;
+         k1 = m + aij->col->j, a1 = aij->val;
+         /* take second term */
+         aij = aij->r_next;
+         if (aij == NULL) continue;
+         k2 = m + aij->col->j, a2 = aij->val;
+         /* there must be only two terms */
+         if (aij->r_next != NULL) continue;
+         /* interchange terms, if needed */
+         if (!mir->isint[k1] && mir->isint[k2])
+            ;
+         else if (mir->isint[k1] && !mir->isint[k2])
+         {  k2 = k1, a2 = a1;
+            k1 = m + aij->col->j, a1 = aij->val;
+         }
+         else
+         {  /* both terms are either continuous or integer */
+            continue;
+         }
+         /* x[k2] should be double-bounded */
+         if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX ||
+             mir->lb[k2] == mir->ub[k2]) continue;
+         /* change signs, if necessary */
+         if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2;
+         /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1
+            is continuous, x2 is integer */
+         if (a1 > 0.0)
+         {  /* x1 >= - (a2 / a1) * x2 */
+            if (mir->vlb[k1] == 0)
+            {  /* set variable lower bound for x1 */
+               mir->lb[k1] = - a2 / a1;
+               mir->vlb[k1] = k2;
+               /* the row should not be used */
+               mir->skip[i] = 1;
+            }
+         }
+         else /* a1 < 0.0 */
+         {  /* x1 <= - (a2 / a1) * x2 */
+            if (mir->vub[k1] == 0)
+            {  /* set variable upper bound for x1 */
+               mir->ub[k1] = - a2 / a1;
+               mir->vub[k1] = k2;
+               /* the row should not be used */
+               mir->skip[i] = 1;
+            }
+         }
+      }
+      return;
+}
+
+static void mark_useless_rows(glp_tree *tree, struct MIR *mir)
+{     /* mark rows which should not be used */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      GLPAIJ *aij;
+      int i, k, nv;
+      for (i = 1; i <= m; i++)
+      {  /* free rows should not be used */
+         if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX)
+         {  mir->skip[i] = 1;
+            continue;
+         }
+         nv = 0;
+         for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  k = m + aij->col->j;
+            /* rows with free variables should not be used */
+            if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX)
+            {  mir->skip[i] = 1;
+               break;
+            }
+            /* rows with integer variables having infinite (lower or
+               upper) bound should not be used */
+            if (mir->isint[k] && mir->lb[k] == -DBL_MAX ||
+                mir->isint[k] && mir->ub[k] == +DBL_MAX)
+            {  mir->skip[i] = 1;
+               break;
+            }
+            /* count non-fixed variables */
+            if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 &&
+                  mir->lb[k] == mir->ub[k])) nv++;
+         }
+         /* rows with all variables fixed should not be used */
+         if (nv == 0)
+         {  mir->skip[i] = 1;
+            continue;
+         }
+      }
+      return;
+}
+
+void *ios_mir_init(glp_tree *tree)
+{     /* initialize MIR cut generator */
+      glp_prob *mip = tree->mip;
+      int m = mip->m;
+      int n = mip->n;
+      struct MIR *mir;
+#if _MIR_DEBUG
+      xprintf("ios_mir_init: warning: debug mode enabled\n");
+#endif
+      /* allocate working area */
+      mir = xmalloc(sizeof(struct MIR));
+      mir->m = m;
+      mir->n = n;
+      mir->skip = xcalloc(1+m, sizeof(char));
+      mir->isint = xcalloc(1+m+n, sizeof(char));
+      mir->lb = xcalloc(1+m+n, sizeof(double));
+      mir->vlb = xcalloc(1+m+n, sizeof(int));
+      mir->ub = xcalloc(1+m+n, sizeof(double));
+      mir->vub = xcalloc(1+m+n, sizeof(int));
+      mir->x = xcalloc(1+m+n, sizeof(double));
+      mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int));
+      mir->agg_vec = ios_create_vec(m+n);
+      mir->subst = xcalloc(1+m+n, sizeof(char));
+      mir->mod_vec = ios_create_vec(m+n);
+      mir->cut_vec = ios_create_vec(m+n);
+      /* set global row attributes */
+      set_row_attrib(tree, mir);
+      /* set global column attributes */
+      set_col_attrib(tree, mir);
+      /* set variable bounds */
+      set_var_bounds(tree, mir);
+      /* mark rows which should not be used */
+      mark_useless_rows(tree, mir);
+      return mir;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_mir_gen - generate MIR cuts
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool);
+*
+*  DESCRIPTION
+*
+*  The routine ios_mir_gen generates MIR cuts for the current point and
+*  adds them to the cut pool. */
+
+static void get_current_point(glp_tree *tree, struct MIR *mir)
+{     /* obtain current point */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      int k;
+      for (k = 1; k <= m; k++)
+         mir->x[k] = mip->row[k]->prim;
+      for (k = m+1; k <= m+n; k++)
+         mir->x[k] = mip->col[k-m]->prim;
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_current_point(struct MIR *mir)
+{     /* check current point */
+      int m = mir->m;
+      int n = mir->n;
+      int k, kk;
+      double lb, ub, eps;
+      for (k = 1; k <= m+n; k++)
+      {  /* determine lower bound */
+         lb = mir->lb[k];
+         kk = mir->vlb[k];
+         if (kk != 0)
+         {  xassert(lb != -DBL_MAX);
+            xassert(!mir->isint[k]);
+            xassert(mir->isint[kk]);
+            lb *= mir->x[kk];
+         }
+         /* check lower bound */
+         if (lb != -DBL_MAX)
+         {  eps = 1e-6 * (1.0 + fabs(lb));
+            xassert(mir->x[k] >= lb - eps);
+         }
+         /* determine upper bound */
+         ub = mir->ub[k];
+         kk = mir->vub[k];
+         if (kk != 0)
+         {  xassert(ub != +DBL_MAX);
+            xassert(!mir->isint[k]);
+            xassert(mir->isint[kk]);
+            ub *= mir->x[kk];
+         }
+         /* check upper bound */
+         if (ub != +DBL_MAX)
+         {  eps = 1e-6 * (1.0 + fabs(ub));
+            xassert(mir->x[k] <= ub + eps);
+         }
+      }
+      return;
+}
+#endif
+
+static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i)
+{     /* use original i-th row as initial aggregated constraint */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      GLPAIJ *aij;
+      xassert(1 <= i && i <= m);
+      xassert(!mir->skip[i]);
+      /* mark i-th row in order not to use it in the same aggregated
+         constraint */
+      mir->skip[i] = 2;
+      mir->agg_cnt = 1;
+      mir->agg_row[1] = i;
+      /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary
+         variable of row i, x[m+j] are structural variables */
+      ios_clear_vec(mir->agg_vec);
+      ios_set_vj(mir->agg_vec, i, 1.0);
+      for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val);
+      mir->agg_rhs = 0.0;
+#if _MIR_DEBUG
+      ios_check_vec(mir->agg_vec);
+#endif
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_agg_row(struct MIR *mir)
+{     /* check aggregated constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k;
+      double r, big;
+      /* compute the residual r = sum a[k] * x[k] - b and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         r += mir->agg_vec->val[j] * mir->x[k];
+         if (big < fabs(mir->agg_vec->val[j]))
+            big = fabs(mir->agg_vec->val[j]);
+      }
+      r -= mir->agg_rhs;
+      if (big < fabs(mir->agg_rhs))
+         big = fabs(mir->agg_rhs);
+      /* the residual must be close to zero */
+      xassert(fabs(r) <= 1e-6 * big);
+      return;
+}
+#endif
+
+static void subst_fixed_vars(struct MIR *mir)
+{     /* substitute fixed variables into aggregated constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k;
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->vlb[k] == 0 && mir->vub[k] == 0 &&
+             mir->lb[k] == mir->ub[k])
+         {  /* x[k] is fixed */
+            mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k];
+            mir->agg_vec->val[j] = 0.0;
+         }
+      }
+      /* remove terms corresponding to fixed variables */
+      ios_clean_vec(mir->agg_vec, DBL_EPSILON);
+#if _MIR_DEBUG
+      ios_check_vec(mir->agg_vec);
+#endif
+      return;
+}
+
+static void bound_subst_heur(struct MIR *mir)
+{     /* bound substitution heuristic */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk;
+      double d1, d2;
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k]) continue; /* skip integer variable */
+         /* compute distance from x[k] to its lower bound */
+         kk = mir->vlb[k];
+         if (kk == 0)
+         {  if (mir->lb[k] == -DBL_MAX)
+               d1 = DBL_MAX;
+            else
+               d1 = mir->x[k] - mir->lb[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->lb[k] != -DBL_MAX);
+            d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         /* compute distance from x[k] to its upper bound */
+         kk = mir->vub[k];
+         if (kk == 0)
+         {  if (mir->vub[k] == +DBL_MAX)
+               d2 = DBL_MAX;
+            else
+               d2 = mir->ub[k] - mir->x[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->ub[k] != +DBL_MAX);
+            d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         /* x[k] cannot be free */
+         xassert(d1 != DBL_MAX || d2 != DBL_MAX);
+         /* choose the bound which is closer to x[k] */
+         xassert(mir->subst[k] == '?');
+         if (d1 <= d2)
+            mir->subst[k] = 'L';
+         else
+            mir->subst[k] = 'U';
+      }
+      return;
+}
+
+static void build_mod_row(struct MIR *mir)
+{     /* substitute bounds and build modified constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, jj, k, kk;
+      /* initially modified constraint is aggregated constraint */
+      ios_copy_vec(mir->mod_vec, mir->agg_vec);
+      mir->mod_rhs = mir->agg_rhs;
+#if _MIR_DEBUG
+      ios_check_vec(mir->mod_vec);
+#endif
+      /* substitute bounds for continuous variables; note that due to
+         substitution of variable bounds additional terms may appear in
+         modified constraint */
+      for (j = mir->mod_vec->nnz; j >= 1; j--)
+      {  k = mir->mod_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k]) continue; /* skip integer variable */
+         if (mir->subst[k] == 'L')
+         {  /* x[k] = (lower bound) + x'[k] */
+            xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+            {  /* x[k] = lb[k] + x'[k] */
+               mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
+            }
+            else
+            {  /* x[k] = lb[k] * x[kk] + x'[k] */
+               xassert(mir->isint[kk]);
+               jj = mir->mod_vec->pos[kk];
+               if (jj == 0)
+               {  ios_set_vj(mir->mod_vec, kk, 1.0);
+                  jj = mir->mod_vec->pos[kk];
+                  mir->mod_vec->val[jj] = 0.0;
+               }
+               mir->mod_vec->val[jj] +=
+                  mir->mod_vec->val[j] * mir->lb[k];
+            }
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x[k] = (upper bound) - x'[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+            {  /* x[k] = ub[k] - x'[k] */
+               mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
+            }
+            else
+            {  /* x[k] = ub[k] * x[kk] - x'[k] */
+               xassert(mir->isint[kk]);
+               jj = mir->mod_vec->pos[kk];
+               if (jj == 0)
+               {  ios_set_vj(mir->mod_vec, kk, 1.0);
+                  jj = mir->mod_vec->pos[kk];
+                  mir->mod_vec->val[jj] = 0.0;
+               }
+               mir->mod_vec->val[jj] +=
+                  mir->mod_vec->val[j] * mir->ub[k];
+            }
+            mir->mod_vec->val[j] = - mir->mod_vec->val[j];
+         }
+         else
+            xassert(k != k);
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->mod_vec);
+#endif
+      /* substitute bounds for integer variables */
+      for (j = 1; j <= mir->mod_vec->nnz; j++)
+      {  k = mir->mod_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (!mir->isint[k]) continue; /* skip continuous variable */
+         xassert(mir->subst[k] == '?');
+         xassert(mir->vlb[k] == 0 && mir->vub[k] == 0);
+         xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX);
+         if (fabs(mir->lb[k]) <= fabs(mir->ub[k]))
+         {  /* x[k] = lb[k] + x'[k] */
+            mir->subst[k] = 'L';
+            mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k];
+         }
+         else
+         {  /* x[k] = ub[k] - x'[k] */
+            mir->subst[k] = 'U';
+            mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k];
+            mir->mod_vec->val[j] = - mir->mod_vec->val[j];
+         }
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->mod_vec);
+#endif
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_mod_row(struct MIR *mir)
+{     /* check modified constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk;
+      double r, big, x;
+      /* compute the residual r = sum a'[k] * x'[k] - b' and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->mod_vec->nnz; j++)
+      {  k = mir->mod_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->subst[k] == 'L')
+         {  /* x'[k] = x[k] - (lower bound) */
+            xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+               x = mir->x[k] - mir->lb[k];
+            else
+               x = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x'[k] = (upper bound) - x[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+               x = mir->ub[k] - mir->x[k];
+            else
+               x = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         else
+            xassert(k != k);
+         r += mir->mod_vec->val[j] * x;
+         if (big < fabs(mir->mod_vec->val[j]))
+            big = fabs(mir->mod_vec->val[j]);
+      }
+      r -= mir->mod_rhs;
+      if (big < fabs(mir->mod_rhs))
+         big = fabs(mir->mod_rhs);
+      /* the residual must be close to zero */
+      xassert(fabs(r) <= 1e-6 * big);
+      return;
+}
+#endif
+
+/***********************************************************************
+*  mir_ineq - construct MIR inequality
+*
+*  Given the single constraint mixed integer set
+*
+*                    |N|
+*     X = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s},
+*                    +      +  j in N
+*
+*  this routine constructs the mixed integer rounding (MIR) inequality
+*
+*     sum   alpha[j] * x[j] <= beta + gamma * s,
+*    j in N
+*
+*  which is valid for X.
+*
+*  If the MIR inequality has been successfully constructed, the routine
+*  returns zero. Otherwise, if b is close to nearest integer, there may
+*  be numeric difficulties due to big coefficients; so in this case the
+*  routine returns non-zero. */
+
+static int mir_ineq(const int n, const double a[], const double b,
+      double alpha[], double *beta, double *gamma)
+{     int j;
+      double f, t;
+      if (fabs(b - floor(b + .5)) < 0.01)
+         return 1;
+      f = b - floor(b);
+      for (j = 1; j <= n; j++)
+      {  t = (a[j] - floor(a[j])) - f;
+         if (t <= 0.0)
+            alpha[j] = floor(a[j]);
+         else
+            alpha[j] = floor(a[j]) + t / (1.0 - f);
+      }
+      *beta = floor(b);
+      *gamma = 1.0 / (1.0 - f);
+      return 0;
+}
+
+/***********************************************************************
+*  cmir_ineq - construct c-MIR inequality
+*
+*  Given the mixed knapsack set
+*
+*      MK              |N|
+*     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
+*                      +      +  j in N
+*
+*             x[j] <= u[j]},
+*
+*  a subset C of variables to be complemented, and a divisor delta > 0,
+*  this routine constructs the complemented MIR (c-MIR) inequality
+*
+*     sum   alpha[j] * x[j] <= beta + gamma * s,
+*    j in N
+*                      MK
+*  which is valid for X  .
+*
+*  If the c-MIR inequality has been successfully constructed, the
+*  routine returns zero. Otherwise, if there is a risk of numerical
+*  difficulties due to big coefficients (see comments to the routine
+*  mir_ineq), the routine cmir_ineq returns non-zero. */
+
+static int cmir_ineq(const int n, const double a[], const double b,
+      const double u[], const char cset[], const double delta,
+      double alpha[], double *beta, double *gamma)
+{     int j;
+      double *aa, bb;
+      aa = alpha, bb = b;
+      for (j = 1; j <= n; j++)
+      {  aa[j] = a[j] / delta;
+         if (cset[j])
+            aa[j] = - aa[j], bb -= a[j] * u[j];
+      }
+      bb /= delta;
+      if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1;
+      for (j = 1; j <= n; j++)
+      {  if (cset[j])
+            alpha[j] = - alpha[j], *beta += alpha[j] * u[j];
+      }
+      *gamma /= delta;
+      return 0;
+}
+
+/***********************************************************************
+*  cmir_sep - c-MIR separation heuristic
+*
+*  Given the mixed knapsack set
+*
+*      MK              |N|
+*     X   = {(x,s) in Z    x R  : sum   a[j] * x[j] <= b + s,
+*                      +      +  j in N
+*
+*             x[j] <= u[j]}
+*
+*                           *   *
+*  and a fractional point (x , s ), this routine tries to construct
+*  c-MIR inequality
+*
+*     sum   alpha[j] * x[j] <= beta + gamma * s,
+*    j in N
+*                      MK
+*  which is valid for X   and has (desirably maximal) violation at the
+*  fractional point given. This is attained by choosing an appropriate
+*  set C of variables to be complemented and a divisor delta > 0, which
+*  together define corresponding c-MIR inequality.
+*
+*  If a violated c-MIR inequality has been successfully constructed,
+*  the routine returns its violation:
+*
+*                       *                      *
+*     sum   alpha[j] * x [j] - beta - gamma * s ,
+*    j in N
+*
+*  which is positive. In case of failure the routine returns zero. */
+
+struct vset { int j; double v; };
+
+static int cmir_cmp(const void *p1, const void *p2)
+{     const struct vset *v1 = p1, *v2 = p2;
+      if (v1->v < v2->v) return -1;
+      if (v1->v > v2->v) return +1;
+      return 0;
+}
+
+static double cmir_sep(const int n, const double a[], const double b,
+      const double u[], const double x[], const double s,
+      double alpha[], double *beta, double *gamma)
+{     int fail, j, k, nv, v;
+      double delta, eps, d_try[1+3], r, r_best;
+      char *cset;
+      struct vset *vset;
+      /* allocate working arrays */
+      cset = xcalloc(1+n, sizeof(char));
+      vset = xcalloc(1+n, sizeof(struct vset));
+      /* choose initial C */
+      for (j = 1; j <= n; j++)
+         cset[j] = (char)(x[j] >= 0.5 * u[j]);
+      /* choose initial delta */
+      r_best = delta = 0.0;
+      for (j = 1; j <= n; j++)
+      {  xassert(a[j] != 0.0);
+         /* if x[j] is close to its bounds, skip it */
+         eps = 1e-9 * (1.0 + fabs(u[j]));
+         if (x[j] < eps || x[j] > u[j] - eps) continue;
+         /* try delta = |a[j]| to construct c-MIR inequality */
+         fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta,
+            gamma);
+         if (fail) continue;
+         /* compute violation */
+         r = - (*beta) - (*gamma) * s;
+         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+         if (r_best < r) r_best = r, delta = fabs(a[j]);
+      }
+      if (r_best < 0.001) r_best = 0.0;
+      if (r_best == 0.0) goto done;
+      xassert(delta > 0.0);
+      /* try to increase violation by dividing delta by 2, 4, and 8,
+         respectively */
+      d_try[1] = delta / 2.0;
+      d_try[2] = delta / 4.0;
+      d_try[3] = delta / 8.0;
+      for (j = 1; j <= 3; j++)
+      {  /* construct c-MIR inequality */
+         fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta,
+            gamma);
+         if (fail) continue;
+         /* compute violation */
+         r = - (*beta) - (*gamma) * s;
+         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+         if (r_best < r) r_best = r, delta = d_try[j];
+      }
+      /* build subset of variables lying strictly between their bounds
+         and order it by nondecreasing values of |x[j] - u[j]/2| */
+      nv = 0;
+      for (j = 1; j <= n; j++)
+      {  /* if x[j] is close to its bounds, skip it */
+         eps = 1e-9 * (1.0 + fabs(u[j]));
+         if (x[j] < eps || x[j] > u[j] - eps) continue;
+         /* add x[j] to the subset */
+         nv++;
+         vset[nv].j = j;
+         vset[nv].v = fabs(x[j] - 0.5 * u[j]);
+      }
+      qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp);
+      /* try to increase violation by successively complementing each
+         variable in the subset */
+      for (v = 1; v <= nv; v++)
+      {  j = vset[v].j;
+         /* replace x[j] by its complement or vice versa */
+         cset[j] = (char)!cset[j];
+         /* construct c-MIR inequality */
+         fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
+         /* restore the variable */
+         cset[j] = (char)!cset[j];
+         /* do not replace the variable in case of failure */
+         if (fail) continue;
+         /* compute violation */
+         r = - (*beta) - (*gamma) * s;
+         for (k = 1; k <= n; k++) r += alpha[k] * x[k];
+         if (r_best < r) r_best = r, cset[j] = (char)!cset[j];
+      }
+      /* construct the best c-MIR inequality chosen */
+      fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma);
+      xassert(!fail);
+done: /* free working arrays */
+      xfree(cset);
+      xfree(vset);
+      /* return to the calling routine */
+      return r_best;
+}
+
+static double generate(struct MIR *mir)
+{     /* try to generate violated c-MIR cut for modified constraint */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk, nint;
+      double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma;
+      ios_copy_vec(mir->cut_vec, mir->mod_vec);
+      mir->cut_rhs = mir->mod_rhs;
+      /* remove small terms, which can appear due to substitution of
+         variable bounds */
+      ios_clean_vec(mir->cut_vec, DBL_EPSILON);
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      /* remove positive continuous terms to obtain MK relaxation */
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0)
+            mir->cut_vec->val[j] = 0.0;
+      }
+      ios_clean_vec(mir->cut_vec, 0.0);
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      /* move integer terms to the beginning of the sparse vector and
+         determine the number of integer variables */
+      nint = 0;
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k])
+         {  double temp;
+            nint++;
+            /* interchange elements [nint] and [j] */
+            kk = mir->cut_vec->ind[nint];
+            mir->cut_vec->pos[k] = nint;
+            mir->cut_vec->pos[kk] = j;
+            mir->cut_vec->ind[nint] = k;
+            mir->cut_vec->ind[j] = kk;
+            temp = mir->cut_vec->val[nint];
+            mir->cut_vec->val[nint] = mir->cut_vec->val[j];
+            mir->cut_vec->val[j] = temp;
+         }
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      /* if there is no integer variable, nothing to generate */
+      if (nint == 0) goto done;
+      /* allocate working arrays */
+      u = xcalloc(1+nint, sizeof(double));
+      x = xcalloc(1+nint, sizeof(double));
+      alpha = xcalloc(1+nint, sizeof(double));
+      /* determine u and x */
+      for (j = 1; j <= nint; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(m+1 <= k && k <= m+n);
+         xassert(mir->isint[k]);
+         u[j] = mir->ub[k] - mir->lb[k];
+         xassert(u[j] >= 1.0);
+         if (mir->subst[k] == 'L')
+            x[j] = mir->x[k] - mir->lb[k];
+         else if (mir->subst[k] == 'U')
+            x[j] = mir->ub[k] - mir->x[k];
+         else
+            xassert(k != k);
+         xassert(x[j] >= -0.001);
+         if (x[j] < 0.0) x[j] = 0.0;
+      }
+      /* compute s = - sum of continuous terms */
+      s = 0.0;
+      for (j = nint+1; j <= mir->cut_vec->nnz; j++)
+      {  double x;
+         k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         /* must be continuous */
+         xassert(!mir->isint[k]);
+         if (mir->subst[k] == 'L')
+         {  xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+               x = mir->x[k] - mir->lb[k];
+            else
+               x = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         else if (mir->subst[k] == 'U')
+         {  xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+               x = mir->ub[k] - mir->x[k];
+            else
+               x = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         else
+            xassert(k != k);
+         xassert(x >= -0.001);
+         if (x < 0.0) x = 0.0;
+         s -= mir->cut_vec->val[j] * x;
+      }
+      xassert(s >= 0.0);
+      /* apply heuristic to obtain most violated c-MIR inequality */
+      b = mir->cut_rhs;
+      r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha,
+         &beta, &gamma);
+      if (r_best == 0.0) goto skip;
+      xassert(r_best > 0.0);
+      /* convert to raw cut */
+      /* sum alpha[j] * x[j] <= beta + gamma * s */
+      for (j = 1; j <= nint; j++)
+         mir->cut_vec->val[j] = alpha[j];
+      for (j = nint+1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         if (k <= m+n) mir->cut_vec->val[j] *= gamma;
+      }
+      mir->cut_rhs = beta;
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+skip: /* free working arrays */
+      xfree(u);
+      xfree(x);
+      xfree(alpha);
+done: return r_best;
+}
+
+#if _MIR_DEBUG
+static void check_raw_cut(struct MIR *mir, double r_best)
+{     /* check raw cut before back bound substitution */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, kk;
+      double r, big, x;
+      /* compute the residual r = sum a[k] * x[k] - b and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->subst[k] == 'L')
+         {  xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+               x = mir->x[k] - mir->lb[k];
+            else
+               x = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         else if (mir->subst[k] == 'U')
+         {  xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+               x = mir->ub[k] - mir->x[k];
+            else
+               x = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         else
+            xassert(k != k);
+         r += mir->cut_vec->val[j] * x;
+         if (big < fabs(mir->cut_vec->val[j]))
+            big = fabs(mir->cut_vec->val[j]);
+      }
+      r -= mir->cut_rhs;
+      if (big < fabs(mir->cut_rhs))
+         big = fabs(mir->cut_rhs);
+      /* the residual must be close to r_best */
+      xassert(fabs(r - r_best) <= 1e-6 * big);
+      return;
+}
+#endif
+
+static void back_subst(struct MIR *mir)
+{     /* back substitution of original bounds */
+      int m = mir->m;
+      int n = mir->n;
+      int j, jj, k, kk;
+      /* at first, restore bounds of integer variables (because on
+         restoring variable bounds of continuous variables we need
+         original, not shifted, bounds of integer variables) */
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (!mir->isint[k]) continue; /* skip continuous */
+         if (mir->subst[k] == 'L')
+         {  /* x'[k] = x[k] - lb[k] */
+            xassert(mir->lb[k] != -DBL_MAX);
+            xassert(mir->vlb[k] == 0);
+            mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x'[k] = ub[k] - x[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            xassert(mir->vub[k] == 0);
+            mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
+            mir->cut_vec->val[j] = - mir->cut_vec->val[j];
+         }
+         else
+            xassert(k != k);
+      }
+      /* now restore bounds of continuous variables */
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (mir->isint[k]) continue; /* skip integer */
+         if (mir->subst[k] == 'L')
+         {  /* x'[k] = x[k] - (lower bound) */
+            xassert(mir->lb[k] != -DBL_MAX);
+            kk = mir->vlb[k];
+            if (kk == 0)
+            {  /* x'[k] = x[k] - lb[k] */
+               mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k];
+            }
+            else
+            {  /* x'[k] = x[k] - lb[k] * x[kk] */
+               jj = mir->cut_vec->pos[kk];
+#if 0
+               xassert(jj != 0);
+#else
+               if (jj == 0)
+               {  ios_set_vj(mir->cut_vec, kk, 1.0);
+                  jj = mir->cut_vec->pos[kk];
+                  xassert(jj != 0);
+                  mir->cut_vec->val[jj] = 0.0;
+               }
+#endif
+               mir->cut_vec->val[jj] -= mir->cut_vec->val[j] *
+                  mir->lb[k];
+            }
+         }
+         else if (mir->subst[k] == 'U')
+         {  /* x'[k] = (upper bound) - x[k] */
+            xassert(mir->ub[k] != +DBL_MAX);
+            kk = mir->vub[k];
+            if (kk == 0)
+            {  /* x'[k] = ub[k] - x[k] */
+               mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k];
+            }
+            else
+            {  /* x'[k] = ub[k] * x[kk] - x[k] */
+               jj = mir->cut_vec->pos[kk];
+               if (jj == 0)
+               {  ios_set_vj(mir->cut_vec, kk, 1.0);
+                  jj = mir->cut_vec->pos[kk];
+                  xassert(jj != 0);
+                  mir->cut_vec->val[jj] = 0.0;
+               }
+               mir->cut_vec->val[jj] += mir->cut_vec->val[j] *
+                  mir->ub[k];
+            }
+            mir->cut_vec->val[j] = - mir->cut_vec->val[j];
+         }
+         else
+            xassert(k != k);
+      }
+#if _MIR_DEBUG
+      ios_check_vec(mir->cut_vec);
+#endif
+      return;
+}
+
+#if _MIR_DEBUG
+static void check_cut_row(struct MIR *mir, double r_best)
+{     /* check the cut after back bound substitution or elimination of
+         auxiliary variables */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k;
+      double r, big;
+      /* compute the residual r = sum a[k] * x[k] - b and determine
+         big = max(1, |a[k]|, |b|) */
+      r = 0.0, big = 1.0;
+      for (j = 1; j <= mir->cut_vec->nnz; j++)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         r += mir->cut_vec->val[j] * mir->x[k];
+         if (big < fabs(mir->cut_vec->val[j]))
+            big = fabs(mir->cut_vec->val[j]);
+      }
+      r -= mir->cut_rhs;
+      if (big < fabs(mir->cut_rhs))
+         big = fabs(mir->cut_rhs);
+      /* the residual must be close to r_best */
+      xassert(fabs(r - r_best) <= 1e-6 * big);
+      return;
+}
+#endif
+
+static void subst_aux_vars(glp_tree *tree, struct MIR *mir)
+{     /* final substitution to eliminate auxiliary variables */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      GLPAIJ *aij;
+      int j, k, kk, jj;
+      for (j = mir->cut_vec->nnz; j >= 1; j--)
+      {  k = mir->cut_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (k > m) continue; /* skip structurals */
+         for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next)
+         {  kk = m + aij->col->j; /* structural */
+            jj = mir->cut_vec->pos[kk];
+            if (jj == 0)
+            {  ios_set_vj(mir->cut_vec, kk, 1.0);
+               jj = mir->cut_vec->pos[kk];
+               mir->cut_vec->val[jj] = 0.0;
+            }
+            mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val;
+         }
+         mir->cut_vec->val[j] = 0.0;
+      }
+      ios_clean_vec(mir->cut_vec, 0.0);
+      return;
+}
+
+static void add_cut(glp_tree *tree, struct MIR *mir)
+{     /* add constructed cut inequality to the cut pool */
+      int m = mir->m;
+      int n = mir->n;
+      int j, k, len;
+      int *ind = xcalloc(1+n, sizeof(int));
+      double *val = xcalloc(1+n, sizeof(double));
+      len = 0;
+      for (j = mir->cut_vec->nnz; j >= 1; j--)
+      {  k = mir->cut_vec->ind[j];
+         xassert(m+1 <= k && k <= m+n);
+         len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j];
+      }
+#if 0
+      ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP,
+         mir->cut_rhs);
+#else
+      glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP,
+         mir->cut_rhs);
+#endif
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+static int aggregate_row(glp_tree *tree, struct MIR *mir)
+{     /* try to aggregate another row */
+      glp_prob *mip = tree->mip;
+      int m = mir->m;
+      int n = mir->n;
+      GLPAIJ *aij;
+      IOSVEC *v;
+      int ii, j, jj, k, kk, kappa = 0, ret = 0;
+      double d1, d2, d, d_max = 0.0;
+      /* choose appropriate structural variable in the aggregated row
+         to be substituted */
+      for (j = 1; j <= mir->agg_vec->nnz; j++)
+      {  k = mir->agg_vec->ind[j];
+         xassert(1 <= k && k <= m+n);
+         if (k <= m) continue; /* skip auxiliary var */
+         if (mir->isint[k]) continue; /* skip integer var */
+         if (fabs(mir->agg_vec->val[j]) < 0.001) continue;
+         /* compute distance from x[k] to its lower bound */
+         kk = mir->vlb[k];
+         if (kk == 0)
+         {  if (mir->lb[k] == -DBL_MAX)
+               d1 = DBL_MAX;
+            else
+               d1 = mir->x[k] - mir->lb[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->lb[k] != -DBL_MAX);
+            d1 = mir->x[k] - mir->lb[k] * mir->x[kk];
+         }
+         /* compute distance from x[k] to its upper bound */
+         kk = mir->vub[k];
+         if (kk == 0)
+         {  if (mir->vub[k] == +DBL_MAX)
+               d2 = DBL_MAX;
+            else
+               d2 = mir->ub[k] - mir->x[k];
+         }
+         else
+         {  xassert(1 <= kk && kk <= m+n);
+            xassert(mir->isint[kk]);
+            xassert(mir->ub[k] != +DBL_MAX);
+            d2 = mir->ub[k] * mir->x[kk] - mir->x[k];
+         }
+         /* x[k] cannot be free */
+         xassert(d1 != DBL_MAX || d2 != DBL_MAX);
+         /* d = min(d1, d2) */
+         d = (d1 <= d2 ? d1 : d2);
+         xassert(d != DBL_MAX);
+         /* should not be close to corresponding bound */
+         if (d < 0.001) continue;
+         if (d_max < d) d_max = d, kappa = k;
+      }
+      if (kappa == 0)
+      {  /* nothing chosen */
+         ret = 1;
+         goto done;
+      }
+      /* x[kappa] has been chosen */
+      xassert(m+1 <= kappa && kappa <= m+n);
+      xassert(!mir->isint[kappa]);
+      /* find another row, which have not been used yet, to eliminate
+         x[kappa] from the aggregated row */
+      for (ii = 1; ii <= m; ii++)
+      {  if (mir->skip[ii]) continue;
+         for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
+            if (aij->col->j == kappa - m) break;
+         if (aij != NULL && fabs(aij->val) >= 0.001) break;
+      }
+      if (ii > m)
+      {  /* nothing found */
+         ret = 2;
+         goto done;
+      }
+      /* row ii has been found; include it in the aggregated list */
+      mir->agg_cnt++;
+      xassert(mir->agg_cnt <= MAXAGGR);
+      mir->agg_row[mir->agg_cnt] = ii;
+      mir->skip[ii] = 2;
+      /* v := new row */
+      v = ios_create_vec(m+n);
+      ios_set_vj(v, ii, 1.0);
+      for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next)
+         ios_set_vj(v, m + aij->col->j, - aij->val);
+#if _MIR_DEBUG
+      ios_check_vec(v);
+#endif
+      /* perform gaussian elimination to remove x[kappa] */
+      j = mir->agg_vec->pos[kappa];
+      xassert(j != 0);
+      jj = v->pos[kappa];
+      xassert(jj != 0);
+      ios_linear_comb(mir->agg_vec,
+         - mir->agg_vec->val[j] / v->val[jj], v);
+      ios_delete_vec(v);
+      ios_set_vj(mir->agg_vec, kappa, 0.0);
+#if _MIR_DEBUG
+      ios_check_vec(mir->agg_vec);
+#endif
+done: return ret;
+}
+
+void ios_mir_gen(glp_tree *tree, void *gen)
+{     /* main routine to generate MIR cuts */
+      glp_prob *mip = tree->mip;
+      struct MIR *mir = gen;
+      int m = mir->m;
+      int n = mir->n;
+      int i;
+      double r_best;
+      xassert(mip->m >= m);
+      xassert(mip->n == n);
+      /* obtain current point */
+      get_current_point(tree, mir);
+#if _MIR_DEBUG
+      /* check current point */
+      check_current_point(mir);
+#endif
+      /* reset bound substitution flags */
+      memset(&mir->subst[1], '?', m+n);
+      /* try to generate a set of violated MIR cuts */
+      for (i = 1; i <= m; i++)
+      {  if (mir->skip[i]) continue;
+         /* use original i-th row as initial aggregated constraint */
+         initial_agg_row(tree, mir, i);
+loop:    ;
+#if _MIR_DEBUG
+         /* check aggregated row */
+         check_agg_row(mir);
+#endif
+         /* substitute fixed variables into aggregated constraint */
+         subst_fixed_vars(mir);
+#if _MIR_DEBUG
+         /* check aggregated row */
+         check_agg_row(mir);
+#endif
+#if _MIR_DEBUG
+         /* check bound substitution flags */
+         {  int k;
+            for (k = 1; k <= m+n; k++)
+               xassert(mir->subst[k] == '?');
+         }
+#endif
+         /* apply bound substitution heuristic */
+         bound_subst_heur(mir);
+         /* substitute bounds and build modified constraint */
+         build_mod_row(mir);
+#if _MIR_DEBUG
+         /* check modified row */
+         check_mod_row(mir);
+#endif
+         /* try to generate violated c-MIR cut for modified row */
+         r_best = generate(mir);
+         if (r_best > 0.0)
+         {  /* success */
+#if _MIR_DEBUG
+            /* check raw cut before back bound substitution */
+            check_raw_cut(mir, r_best);
+#endif
+            /* back substitution of original bounds */
+            back_subst(mir);
+#if _MIR_DEBUG
+            /* check the cut after back bound substitution */
+            check_cut_row(mir, r_best);
+#endif
+            /* final substitution to eliminate auxiliary variables */
+            subst_aux_vars(tree, mir);
+#if _MIR_DEBUG
+            /* check the cut after elimination of auxiliaries */
+            check_cut_row(mir, r_best);
+#endif
+            /* add constructed cut inequality to the cut pool */
+            add_cut(tree, mir);
+         }
+         /* reset bound substitution flags */
+         {  int j, k;
+            for (j = 1; j <= mir->mod_vec->nnz; j++)
+            {  k = mir->mod_vec->ind[j];
+               xassert(1 <= k && k <= m+n);
+               xassert(mir->subst[k] != '?');
+               mir->subst[k] = '?';
+            }
+         }
+         if (r_best == 0.0)
+         {  /* failure */
+            if (mir->agg_cnt < MAXAGGR)
+            {  /* try to aggregate another row */
+               if (aggregate_row(tree, mir) == 0) goto loop;
+            }
+         }
+         /* unmark rows used in the aggregated constraint */
+         {  int k, ii;
+            for (k = 1; k <= mir->agg_cnt; k++)
+            {  ii = mir->agg_row[k];
+               xassert(1 <= ii && ii <= m);
+               xassert(mir->skip[ii] == 2);
+               mir->skip[ii] = 0;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_mir_term - terminate MIR cut generator
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_mir_term(void *gen);
+*
+*  DESCRIPTION
+*
+*  The routine ios_mir_term deletes the MIR cut generator working area
+*  freeing all the memory allocated to it. */
+
+void ios_mir_term(void *gen)
+{     struct MIR *mir = gen;
+      xfree(mir->skip);
+      xfree(mir->isint);
+      xfree(mir->lb);
+      xfree(mir->vlb);
+      xfree(mir->ub);
+      xfree(mir->vub);
+      xfree(mir->x);
+      xfree(mir->agg_row);
+      ios_delete_vec(mir->agg_vec);
+      xfree(mir->subst);
+      ios_delete_vec(mir->mod_vec);
+      ios_delete_vec(mir->cut_vec);
+      xfree(mir);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpios07.c
===================================================================
--- deps/glpk/src/glpios07.c	(revision 9)
+++ deps/glpk/src/glpios07.c	(revision 9)
@@ -0,0 +1,554 @@
+/* glpios07.c (mixed cover cut generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/*----------------------------------------------------------------------
+-- COVER INEQUALITIES
+--
+-- Consider the set of feasible solutions to 0-1 knapsack problem:
+--
+--    sum a[j]*x[j] <= b,                                            (1)
+--  j in J
+--
+--    x[j] is binary,                                                (2)
+--
+-- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be
+-- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0).
+--
+-- A set C within J is called a cover if
+--
+--    sum a[j] > b.                                                  (3)
+--  j in C
+--
+-- For any cover C the inequality
+--
+--    sum x[j] <= |C| - 1                                            (4)
+--  j in C
+--
+-- is called a cover inequality and is valid for (1)-(2).
+--
+-- MIXED COVER INEQUALITIES
+--
+-- Consider the set of feasible solutions to mixed knapsack problem:
+--
+--    sum a[j]*x[j] + y <= b,                                        (5)
+--  j in J
+--
+--    x[j] is binary,                                                (6)
+--
+--    0 <= y <= u is continuous,                                     (7)
+--
+-- where again we assume that a[j] > 0.
+--
+-- Let C within J be some set. From (1)-(4) it follows that
+--
+--    sum a[j] > b - y                                               (8)
+--  j in C
+--
+-- implies
+--
+--    sum x[j] <= |C| - 1.                                           (9)
+--  j in C
+--
+-- Thus, we need to modify the inequality (9) in such a way that it be
+-- a constraint only if the condition (8) is satisfied.
+--
+-- Consider the following inequality:
+--
+--    sum x[j] <= |C| - t.                                          (10)
+--  j in C
+--
+-- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are
+-- binary variables. On the other hand, if t <= 0, (10) being satisfied
+-- for any values of x[j] is not a constraint.
+--
+-- Let
+--
+--    t' = sum a[j] + y - b.                                        (11)
+--       j in C
+--
+-- It is understood that the condition t' > 0 is equivalent to (8).
+-- Besides, from (6)-(7) it follows that t' has an implied upper bound:
+--
+--    t'max = sum a[j] + u - b.                                     (12)
+--          j in C
+--
+-- This allows to express the parameter t having desired properties:
+--
+--    t = t' / t'max.                                               (13)
+--
+-- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0
+-- is equivalent to (8).
+--
+-- Thus, the inequality (10), where t is given by formula (13) is valid
+-- for (5)-(7).
+--
+-- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and
+-- (10) is transformed to the conditions (3) and (4).
+--
+-- GENERATING MIXED COVER CUTS
+--
+-- To generate a mixed cover cut in the form (10) we need to find such
+-- set C which satisfies to the inequality (8) and for which, in turn,
+-- the inequality (10) is violated in the current point.
+--
+-- Substituting t from (13) to (10) gives:
+--
+--                        1
+--    sum x[j] <= |C| - -----  (sum a[j] + y - b),                  (14)
+--  j in C              t'max j in C
+--
+-- and finally we have the cut inequality in the standard form:
+--
+--    sum x[j] + alfa * y <= beta,                                  (15)
+--  j in C
+--
+-- where:
+--
+--    alfa = 1 / t'max,                                             (16)
+--
+--    beta = |C| - alfa *  (sum a[j] - b).                          (17)
+--                        j in C                                      */
+
+#if 1
+#define MAXTRY 1000
+#else
+#define MAXTRY 10000
+#endif
+
+static int cover2(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *_alfa, double *_beta)
+{     /* try to generate mixed cover cut using two-element cover */
+      int i, j, try = 0, ret = 0;
+      double eps, alfa, beta, temp, rmax = 0.001;
+      eps = 0.001 * (1.0 + fabs(b));
+      for (i = 0+1; i <= n; i++)
+      for (j = i+1; j <= n; j++)
+      {  /* C = {i, j} */
+         try++;
+         if (try > MAXTRY) goto done;
+         /* check if condition (8) is satisfied */
+         if (a[i] + a[j] + y > b + eps)
+         {  /* compute parameters for inequality (15) */
+            temp = a[i] + a[j] - b;
+            alfa = 1.0 / (temp + u);
+            beta = 2.0 - alfa * temp;
+            /* compute violation of inequality (15) */
+            temp = x[i] + x[j] + alfa * y - beta;
+            /* choose C providing maximum violation */
+            if (rmax < temp)
+            {  rmax = temp;
+               cov[1] = i;
+               cov[2] = j;
+               *_alfa = alfa;
+               *_beta = beta;
+               ret = 1;
+            }
+         }
+      }
+done: return ret;
+}
+
+static int cover3(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *_alfa, double *_beta)
+{     /* try to generate mixed cover cut using three-element cover */
+      int i, j, k, try = 0, ret = 0;
+      double eps, alfa, beta, temp, rmax = 0.001;
+      eps = 0.001 * (1.0 + fabs(b));
+      for (i = 0+1; i <= n; i++)
+      for (j = i+1; j <= n; j++)
+      for (k = j+1; k <= n; k++)
+      {  /* C = {i, j, k} */
+         try++;
+         if (try > MAXTRY) goto done;
+         /* check if condition (8) is satisfied */
+         if (a[i] + a[j] + a[k] + y > b + eps)
+         {  /* compute parameters for inequality (15) */
+            temp = a[i] + a[j] + a[k] - b;
+            alfa = 1.0 / (temp + u);
+            beta = 3.0 - alfa * temp;
+            /* compute violation of inequality (15) */
+            temp = x[i] + x[j] + x[k] + alfa * y - beta;
+            /* choose C providing maximum violation */
+            if (rmax < temp)
+            {  rmax = temp;
+               cov[1] = i;
+               cov[2] = j;
+               cov[3] = k;
+               *_alfa = alfa;
+               *_beta = beta;
+               ret = 1;
+            }
+         }
+      }
+done: return ret;
+}
+
+static int cover4(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *_alfa, double *_beta)
+{     /* try to generate mixed cover cut using four-element cover */
+      int i, j, k, l, try = 0, ret = 0;
+      double eps, alfa, beta, temp, rmax = 0.001;
+      eps = 0.001 * (1.0 + fabs(b));
+      for (i = 0+1; i <= n; i++)
+      for (j = i+1; j <= n; j++)
+      for (k = j+1; k <= n; k++)
+      for (l = k+1; l <= n; l++)
+      {  /* C = {i, j, k, l} */
+         try++;
+         if (try > MAXTRY) goto done;
+         /* check if condition (8) is satisfied */
+         if (a[i] + a[j] + a[k] + a[l] + y > b + eps)
+         {  /* compute parameters for inequality (15) */
+            temp = a[i] + a[j] + a[k] + a[l] - b;
+            alfa = 1.0 / (temp + u);
+            beta = 4.0 - alfa * temp;
+            /* compute violation of inequality (15) */
+            temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta;
+            /* choose C providing maximum violation */
+            if (rmax < temp)
+            {  rmax = temp;
+               cov[1] = i;
+               cov[2] = j;
+               cov[3] = k;
+               cov[4] = l;
+               *_alfa = alfa;
+               *_beta = beta;
+               ret = 1;
+            }
+         }
+      }
+done: return ret;
+}
+
+static int cover(int n, double a[], double b, double u, double x[],
+      double y, int cov[], double *alfa, double *beta)
+{     /* try to generate mixed cover cut;
+         input (see (5)):
+         n        is the number of binary variables;
+         a[1:n]   are coefficients at binary variables;
+         b        is the right-hand side;
+         u        is upper bound of continuous variable;
+         x[1:n]   are values of binary variables at current point;
+         y        is value of continuous variable at current point;
+         output (see (15), (16), (17)):
+         cov[1:r] are indices of binary variables included in cover C,
+                  where r is the set cardinality returned on exit;
+         alfa     coefficient at continuous variable;
+         beta     is the right-hand side; */
+      int j;
+      /* perform some sanity checks */
+      xassert(n >= 2);
+      for (j = 1; j <= n; j++) xassert(a[j] > 0.0);
+#if 1 /* ??? */
+      xassert(b > -1e-5);
+#else
+      xassert(b > 0.0);
+#endif
+      xassert(u >= 0.0);
+      for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0);
+      xassert(0.0 <= y && y <= u);
+      /* try to generate mixed cover cut */
+      if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2;
+      if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3;
+      if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4;
+      return 0;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_cover_cut - generate mixed cover cut.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
+--    double work[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_cover_cut generates a mixed cover cut for a given
+-- row of the MIP problem.
+--
+-- The given row of the MIP problem should be explicitly specified in
+-- the form:
+--
+--    sum{j in J} a[j]*x[j] <= b.                                    (1)
+--
+-- On entry indices (ordinal numbers) of structural variables, which
+-- have non-zero constraint coefficients, should be placed in locations
+-- ind[1], ..., ind[len], and corresponding constraint coefficients
+-- should be placed in locations val[1], ..., val[len]. The right-hand
+-- side b should be stored in location val[0].
+--
+-- The working array work should have at least nb locations, where nb
+-- is the number of binary variables in (1).
+--
+-- The routine generates a mixed cover cut in the same form as (1) and
+-- stores the cut coefficients and right-hand side in the same way as
+-- just described above.
+--
+-- RETURNS
+--
+-- If the cutting plane has been successfully generated, the routine
+-- returns 1 <= len' <= n, which is the number of non-zero coefficients
+-- in the inequality constraint. Otherwise, the routine returns zero. */
+
+static int lpx_cover_cut(LPX *lp, int len, int ind[], double val[],
+      double work[])
+{     int cov[1+4], j, k, nb, newlen, r;
+      double f_min, f_max, alfa, beta, u, *x = work, y;
+      /* substitute and remove fixed variables */
+      newlen = 0;
+      for (k = 1; k <= len; k++)
+      {  j = ind[k];
+         if (lpx_get_col_type(lp, j) == LPX_FX)
+            val[0] -= val[k] * lpx_get_col_lb(lp, j);
+         else
+         {  newlen++;
+            ind[newlen] = ind[k];
+            val[newlen] = val[k];
+         }
+      }
+      len = newlen;
+      /* move binary variables to the beginning of the list so that
+         elements 1, 2, ..., nb correspond to binary variables, and
+         elements nb+1, nb+2, ..., len correspond to rest variables */
+      nb = 0;
+      for (k = 1; k <= len; k++)
+      {  j = ind[k];
+         if (lpx_get_col_kind(lp, j) == LPX_IV &&
+             lpx_get_col_type(lp, j) == LPX_DB &&
+             lpx_get_col_lb(lp, j) == 0.0 &&
+             lpx_get_col_ub(lp, j) == 1.0)
+         {  /* binary variable */
+            int ind_k;
+            double val_k;
+            nb++;
+            ind_k = ind[nb], val_k = val[nb];
+            ind[nb] = ind[k], val[nb] = val[k];
+            ind[k] = ind_k, val[k] = val_k;
+         }
+      }
+      /* now the specified row has the form:
+         sum a[j]*x[j] + sum a[j]*y[j] <= b,
+         where x[j] are binary variables, y[j] are rest variables */
+      /* at least two binary variables are needed */
+      if (nb < 2) return 0;
+      /* compute implied lower and upper bounds for sum a[j]*y[j] */
+      f_min = f_max = 0.0;
+      for (k = nb+1; k <= len; k++)
+      {  j = ind[k];
+         /* both bounds must be finite */
+         if (lpx_get_col_type(lp, j) != LPX_DB) return 0;
+         if (val[k] > 0.0)
+         {  f_min += val[k] * lpx_get_col_lb(lp, j);
+            f_max += val[k] * lpx_get_col_ub(lp, j);
+         }
+         else
+         {  f_min += val[k] * lpx_get_col_ub(lp, j);
+            f_max += val[k] * lpx_get_col_lb(lp, j);
+         }
+      }
+      /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===>
+         sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===>
+         sum a[j]*x[j] + y <= b - f_min,
+         where y = sum a[j]*y[j] - f_min;
+         note that 0 <= y <= u, u = f_max - f_min */
+      /* determine upper bound of y */
+      u = f_max - f_min;
+      /* determine value of y at the current point */
+      y = 0.0;
+      for (k = nb+1; k <= len; k++)
+      {  j = ind[k];
+         y += val[k] * lpx_get_col_prim(lp, j);
+      }
+      y -= f_min;
+      if (y < 0.0) y = 0.0;
+      if (y > u) y = u;
+      /* modify the right-hand side b */
+      val[0] -= f_min;
+      /* now the transformed row has the form:
+         sum a[j]*x[j] + y <= b, where 0 <= y <= u */
+      /* determine values of x[j] at the current point */
+      for (k = 1; k <= nb; k++)
+      {  j = ind[k];
+         x[k] = lpx_get_col_prim(lp, j);
+         if (x[k] < 0.0) x[k] = 0.0;
+         if (x[k] > 1.0) x[k] = 1.0;
+      }
+      /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */
+      for (k = 1; k <= nb; k++)
+      {  if (val[k] < 0.0)
+         {  ind[k] = - ind[k];
+            val[k] = - val[k];
+            val[0] += val[k];
+            x[k] = 1.0 - x[k];
+         }
+      }
+      /* try to generate a mixed cover cut for the transformed row */
+      r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta);
+      if (r == 0) return 0;
+      xassert(2 <= r && r <= 4);
+      /* now the cut is in the form:
+         sum{j in C} x[j] + alfa * y <= beta */
+      /* store the right-hand side beta */
+      ind[0] = 0, val[0] = beta;
+      /* restore the original ordinal numbers of x[j] */
+      for (j = 1; j <= r; j++) cov[j] = ind[cov[j]];
+      /* store cut coefficients at binary variables complementing back
+         the variables having negative row coefficients */
+      xassert(r <= nb);
+      for (k = 1; k <= r; k++)
+      {  if (cov[k] > 0)
+         {  ind[k] = +cov[k];
+            val[k] = +1.0;
+         }
+         else
+         {  ind[k] = -cov[k];
+            val[k] = -1.0;
+            val[0] -= 1.0;
+         }
+      }
+      /* substitute y = sum a[j]*y[j] - f_min */
+      for (k = nb+1; k <= len; k++)
+      {  r++;
+         ind[r] = ind[k];
+         val[r] = alfa * val[k];
+      }
+      val[0] += alfa * f_min;
+      xassert(r <= len);
+      len = r;
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_eval_row - compute explictily specified row.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_eval_row computes the primal value of an explicitly
+-- specified row using current values of structural variables.
+--
+-- The explicitly specified row may be thought as a linear form:
+--
+--    y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n],
+--
+-- where y is an auxiliary variable for this row, a[j] are coefficients
+-- of the linear form, x[m+j] are structural variables.
+--
+-- On entry column indices and numerical values of non-zero elements of
+-- the row should be stored in locations ind[1], ..., ind[len] and
+-- val[1], ..., val[len], where len is the number of non-zero elements.
+-- The array ind and val are not changed on exit.
+--
+-- RETURNS
+--
+-- The routine returns a computed value of y, the auxiliary variable of
+-- the specified row. */
+
+static double lpx_eval_row(LPX *lp, int len, int ind[], double val[])
+{     int n = lpx_get_num_cols(lp);
+      int j, k;
+      double sum = 0.0;
+      if (len < 0)
+         xerror("lpx_eval_row: len = %d; invalid row length\n", len);
+      for (k = 1; k <= len; k++)
+      {  j = ind[k];
+         if (!(1 <= j && j <= n))
+            xerror("lpx_eval_row: j = %d; column number out of range\n",
+               j);
+         sum += val[k] * lpx_get_col_prim(lp, j);
+      }
+      return sum;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_cov_gen - generate mixed cover cuts
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_cov_gen(glp_tree *tree);
+*
+*  DESCRIPTION
+*
+*  The routine ios_cov_gen generates mixed cover cuts for the current
+*  point and adds them to the cut pool. */
+
+void ios_cov_gen(glp_tree *tree)
+{     glp_prob *prob = tree->mip;
+      int m = lpx_get_num_rows(prob);
+      int n = lpx_get_num_cols(prob);
+      int i, k, type, kase, len, *ind;
+      double r, *val, *work;
+      xassert(lpx_get_status(prob) == LPX_OPT);
+      /* allocate working arrays */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      work = xcalloc(1+n, sizeof(double));
+      /* look through all rows */
+      for (i = 1; i <= m; i++)
+      for (kase = 1; kase <= 2; kase++)
+      {  type = lpx_get_row_type(prob, i);
+         if (kase == 1)
+         {  /* consider rows of '<=' type */
+            if (!(type == LPX_UP || type == LPX_DB)) continue;
+            len = lpx_get_mat_row(prob, i, ind, val);
+            val[0] = lpx_get_row_ub(prob, i);
+         }
+         else
+         {  /* consider rows of '>=' type */
+            if (!(type == LPX_LO || type == LPX_DB)) continue;
+            len = lpx_get_mat_row(prob, i, ind, val);
+            for (k = 1; k <= len; k++) val[k] = - val[k];
+            val[0] = - lpx_get_row_lb(prob, i);
+         }
+         /* generate mixed cover cut:
+            sum{j in J} a[j] * x[j] <= b */
+         len = lpx_cover_cut(prob, len, ind, val, work);
+         if (len == 0) continue;
+         /* at the current point the cut inequality is violated, i.e.
+            sum{j in J} a[j] * x[j] - b > 0 */
+         r = lpx_eval_row(prob, len, ind, val) - val[0];
+         if (r < 1e-3) continue;
+         /* add the cut to the cut pool */
+         glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val,
+            GLP_UP, val[0]);
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      xfree(work);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpios08.c
===================================================================
--- deps/glpk/src/glpios08.c	(revision 9)
+++ deps/glpk/src/glpios08.c	(revision 9)
@@ -0,0 +1,907 @@
+/* glpios08.c (clique cut generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+static double get_row_lb(LPX *lp, int i)
+{     /* this routine returns lower bound of row i or -DBL_MAX if the
+         row has no lower bound */
+      double lb;
+      switch (lpx_get_row_type(lp, i))
+      {  case LPX_FR:
+         case LPX_UP:
+            lb = -DBL_MAX;
+            break;
+         case LPX_LO:
+         case LPX_DB:
+         case LPX_FX:
+            lb = lpx_get_row_lb(lp, i);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+static double get_row_ub(LPX *lp, int i)
+{     /* this routine returns upper bound of row i or +DBL_MAX if the
+         row has no upper bound */
+      double ub;
+      switch (lpx_get_row_type(lp, i))
+      {  case LPX_FR:
+         case LPX_LO:
+            ub = +DBL_MAX;
+            break;
+         case LPX_UP:
+         case LPX_DB:
+         case LPX_FX:
+            ub = lpx_get_row_ub(lp, i);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+static double get_col_lb(LPX *lp, int j)
+{     /* this routine returns lower bound of column j or -DBL_MAX if
+         the column has no lower bound */
+      double lb;
+      switch (lpx_get_col_type(lp, j))
+      {  case LPX_FR:
+         case LPX_UP:
+            lb = -DBL_MAX;
+            break;
+         case LPX_LO:
+         case LPX_DB:
+         case LPX_FX:
+            lb = lpx_get_col_lb(lp, j);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return lb;
+}
+
+static double get_col_ub(LPX *lp, int j)
+{     /* this routine returns upper bound of column j or +DBL_MAX if
+         the column has no upper bound */
+      double ub;
+      switch (lpx_get_col_type(lp, j))
+      {  case LPX_FR:
+         case LPX_LO:
+            ub = +DBL_MAX;
+            break;
+         case LPX_UP:
+         case LPX_DB:
+         case LPX_FX:
+            ub = lpx_get_col_ub(lp, j);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return ub;
+}
+
+static int is_binary(LPX *lp, int j)
+{     /* this routine checks if variable x[j] is binary */
+      return
+         lpx_get_col_kind(lp, j) == LPX_IV &&
+         lpx_get_col_type(lp, j) == LPX_DB &&
+         lpx_get_col_lb(lp, j) == 0.0 && lpx_get_col_ub(lp, j) == 1.0;
+}
+
+static double eval_lf_min(LPX *lp, int len, int ind[], double val[])
+{     /* this routine computes the minimum of a specified linear form
+
+            sum a[j]*x[j]
+             j
+
+         using the formula:
+
+            min =   sum   a[j]*lb[j] +   sum   a[j]*ub[j],
+                  j in J+              j in J-
+
+         where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
+         are lower and upper bound of variable x[j], resp. */
+      int j, t;
+      double lb, ub, sum;
+      sum = 0.0;
+      for (t = 1; t <= len; t++)
+      {  j = ind[t];
+         if (val[t] > 0.0)
+         {  lb = get_col_lb(lp, j);
+            if (lb == -DBL_MAX)
+            {  sum = -DBL_MAX;
+               break;
+            }
+            sum += val[t] * lb;
+         }
+         else if (val[t] < 0.0)
+         {  ub = get_col_ub(lp, j);
+            if (ub == +DBL_MAX)
+            {  sum = -DBL_MAX;
+               break;
+            }
+            sum += val[t] * ub;
+         }
+         else
+            xassert(val != val);
+      }
+      return sum;
+}
+
+static double eval_lf_max(LPX *lp, int len, int ind[], double val[])
+{     /* this routine computes the maximum of a specified linear form
+
+            sum a[j]*x[j]
+             j
+
+         using the formula:
+
+            max =   sum   a[j]*ub[j] +   sum   a[j]*lb[j],
+                  j in J+              j in J-
+
+         where J+ = {j: a[j] > 0}, J- = {j: a[j] < 0}, lb[j] and ub[j]
+         are lower and upper bound of variable x[j], resp. */
+      int j, t;
+      double lb, ub, sum;
+      sum = 0.0;
+      for (t = 1; t <= len; t++)
+      {  j = ind[t];
+         if (val[t] > 0.0)
+         {  ub = get_col_ub(lp, j);
+            if (ub == +DBL_MAX)
+            {  sum = +DBL_MAX;
+               break;
+            }
+            sum += val[t] * ub;
+         }
+         else if (val[t] < 0.0)
+         {  lb = get_col_lb(lp, j);
+            if (lb == -DBL_MAX)
+            {  sum = +DBL_MAX;
+               break;
+            }
+            sum += val[t] * lb;
+         }
+         else
+            xassert(val != val);
+      }
+      return sum;
+}
+
+/*----------------------------------------------------------------------
+-- probing - determine logical relation between binary variables.
+--
+-- This routine tentatively sets a binary variable to 0 and then to 1
+-- and examines whether another binary variable is caused to be fixed.
+--
+-- The examination is based only on one row (constraint), which is the
+-- following:
+--
+--    L <= sum a[j]*x[j] <= U.                                       (1)
+--          j
+--
+-- Let x[p] be a probing variable, x[q] be an examined variable. Then
+-- (1) can be written as:
+--
+--    L <=   sum  a[j]*x[j] + a[p]*x[p] + a[q]*x[q] <= U,            (2)
+--         j in J'
+--
+-- where J' = {j: j != p and j != q}.
+--
+-- Let
+--
+--    L' = L - a[p]*x[p],                                            (3)
+--
+--    U' = U - a[p]*x[p],                                            (4)
+--
+-- where x[p] is assumed to be fixed at 0 or 1. So (2) can be rewritten
+-- as follows:
+--
+--    L' <=   sum  a[j]*x[j] + a[q]*x[q] <= U',                      (5)
+--          j in J'
+--
+-- from where we have:
+--
+--    L' -  sum  a[j]*x[j] <= a[q]*x[q] <= U' -  sum  a[j]*x[j].     (6)
+--        j in J'                              j in J'
+--
+-- Thus,
+--
+--    min a[q]*x[q] = L' - MAX,                                      (7)
+--
+--    max a[q]*x[q] = U' - MIN,                                      (8)
+--
+-- where
+--
+--    MIN = min  sum  a[j]*x[j],                                     (9)
+--             j in J'
+--
+--    MAX = max  sum  a[j]*x[j].                                    (10)
+--             j in J'
+--
+-- Formulae (7) and (8) allows determining implied lower and upper
+-- bounds of x[q].
+--
+-- Parameters len, val, L and U specify the constraint (1).
+--
+-- Parameters lf_min and lf_max specify implied lower and upper bounds
+-- of the linear form (1). It is assumed that these bounds are computed
+-- with the routines eval_lf_min and eval_lf_max (see above).
+--
+-- Parameter p specifies the probing variable x[p], which is set to 0
+-- (if set is 0) or to 1 (if set is 1).
+--
+-- Parameter q specifies the examined variable x[q].
+--
+-- On exit the routine returns one of the following codes:
+--
+-- 0 - there is no logical relation between x[p] and x[q];
+-- 1 - x[q] can take only on value 0;
+-- 2 - x[q] can take only on value 1. */
+
+static int probing(int len, double val[], double L, double U,
+      double lf_min, double lf_max, int p, int set, int q)
+{     double temp;
+      xassert(1 <= p && p < q && q <= len);
+      /* compute L' (3) */
+      if (L != -DBL_MAX && set) L -= val[p];
+      /* compute U' (4) */
+      if (U != +DBL_MAX && set) U -= val[p];
+      /* compute MIN (9) */
+      if (lf_min != -DBL_MAX)
+      {  if (val[p] < 0.0) lf_min -= val[p];
+         if (val[q] < 0.0) lf_min -= val[q];
+      }
+      /* compute MAX (10) */
+      if (lf_max != +DBL_MAX)
+      {  if (val[p] > 0.0) lf_max -= val[p];
+         if (val[q] > 0.0) lf_max -= val[q];
+      }
+      /* compute implied lower bound of x[q]; see (7), (8) */
+      if (val[q] > 0.0)
+      {  if (L == -DBL_MAX || lf_max == +DBL_MAX)
+            temp = -DBL_MAX;
+         else
+            temp = (L - lf_max) / val[q];
+      }
+      else
+      {  if (U == +DBL_MAX || lf_min == -DBL_MAX)
+            temp = -DBL_MAX;
+         else
+            temp = (U - lf_min) / val[q];
+      }
+      if (temp > 0.001) return 2;
+      /* compute implied upper bound of x[q]; see (7), (8) */
+      if (val[q] > 0.0)
+      {  if (U == +DBL_MAX || lf_min == -DBL_MAX)
+            temp = +DBL_MAX;
+         else
+            temp = (U - lf_min) / val[q];
+      }
+      else
+      {  if (L == -DBL_MAX || lf_max == +DBL_MAX)
+            temp = +DBL_MAX;
+         else
+            temp = (L - lf_max) / val[q];
+      }
+      if (temp < 0.999) return 1;
+      /* there is no logical relation between x[p] and x[q] */
+      return 0;
+}
+
+struct COG
+{     /* conflict graph; it represents logical relations between binary
+         variables and has a vertex for each binary variable and its
+         complement, and an edge between two vertices when at most one
+         of the variables represented by the vertices can equal one in
+         an optimal solution */
+      int n;
+      /* number of variables */
+      int nb;
+      /* number of binary variables represented in the graph (note that
+         not all binary variables can be represented); vertices which
+         correspond to binary variables have numbers 1, ..., nb while
+         vertices which correspond to complements of binary variables
+         have numbers nb+1, ..., nb+nb */
+      int ne;
+      /* number of edges in the graph */
+      int *vert; /* int vert[1+n]; */
+      /* if x[j] is a binary variable represented in the graph, vert[j]
+         is the vertex number corresponding to x[j]; otherwise vert[j]
+         is zero */
+      int *orig; /* int list[1:nb]; */
+      /* if vert[j] = k > 0, then orig[k] = j */
+      unsigned char *a;
+      /* adjacency matrix of the graph having 2*nb rows and columns;
+         only strict lower triangle is stored in dense packed form */
+};
+
+/*----------------------------------------------------------------------
+-- lpx_create_cog - create the conflict graph.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- void *lpx_create_cog(LPX *lp);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_create_cog creates the conflict graph for a given
+-- problem instance.
+--
+-- RETURNS
+--
+-- If the graph has been created, the routine returns a pointer to it.
+-- Otherwise the routine returns NULL. */
+
+#define MAX_NB 4000
+#define MAX_ROW_LEN 500
+
+static void lpx_add_cog_edge(void *_cog, int i, int j);
+
+static void *lpx_create_cog(LPX *lp)
+{     struct COG *cog = NULL;
+      int m, n, nb, i, j, p, q, len, *ind, *vert, *orig;
+      double L, U, lf_min, lf_max, *val;
+      xprintf("Creating the conflict graph...\n");
+      m = lpx_get_num_rows(lp);
+      n = lpx_get_num_cols(lp);
+      /* determine which binary variables should be included in the
+         conflict graph */
+      nb = 0;
+      vert = xcalloc(1+n, sizeof(int));
+      for (j = 1; j <= n; j++) vert[j] = 0;
+      orig = xcalloc(1+n, sizeof(int));
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  L = get_row_lb(lp, i);
+         U = get_row_ub(lp, i);
+         if (L == -DBL_MAX && U == +DBL_MAX) continue;
+         len = lpx_get_mat_row(lp, i, ind, val);
+         if (len > MAX_ROW_LEN) continue;
+         lf_min = eval_lf_min(lp, len, ind, val);
+         lf_max = eval_lf_max(lp, len, ind, val);
+         for (p = 1; p <= len; p++)
+         {  if (!is_binary(lp, ind[p])) continue;
+            for (q = p+1; q <= len; q++)
+            {  if (!is_binary(lp, ind[q])) continue;
+               if (probing(len, val, L, U, lf_min, lf_max, p, 0, q) ||
+                   probing(len, val, L, U, lf_min, lf_max, p, 1, q))
+               {  /* there is a logical relation */
+                  /* include the first variable in the graph */
+                  j = ind[p];
+                  if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
+                  /* incude the second variable in the graph */
+                  j = ind[q];
+                  if (vert[j] == 0) nb++, vert[j] = nb, orig[nb] = j;
+               }
+            }
+         }
+      }
+      /* if the graph is either empty or has too many vertices, do not
+         create it */
+      if (nb == 0 || nb > MAX_NB)
+      {  xprintf("The conflict graph is either empty or too big\n");
+         xfree(vert);
+         xfree(orig);
+         goto done;
+      }
+      /* create the conflict graph */
+      cog = xmalloc(sizeof(struct COG));
+      cog->n = n;
+      cog->nb = nb;
+      cog->ne = 0;
+      cog->vert = vert;
+      cog->orig = orig;
+      len = nb + nb; /* number of vertices */
+      len = (len * (len - 1)) / 2; /* number of entries in triangle */
+      len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* bytes needed */
+      cog->a = xmalloc(len);
+      memset(cog->a, 0, len);
+      for (j = 1; j <= nb; j++)
+      {  /* add edge between variable and its complement */
+         lpx_add_cog_edge(cog, +orig[j], -orig[j]);
+      }
+      for (i = 1; i <= m; i++)
+      {  L = get_row_lb(lp, i);
+         U = get_row_ub(lp, i);
+         if (L == -DBL_MAX && U == +DBL_MAX) continue;
+         len = lpx_get_mat_row(lp, i, ind, val);
+         if (len > MAX_ROW_LEN) continue;
+         lf_min = eval_lf_min(lp, len, ind, val);
+         lf_max = eval_lf_max(lp, len, ind, val);
+         for (p = 1; p <= len; p++)
+         {  if (!is_binary(lp, ind[p])) continue;
+            for (q = p+1; q <= len; q++)
+            {  if (!is_binary(lp, ind[q])) continue;
+               /* set x[p] to 0 and examine x[q] */
+               switch (probing(len, val, L, U, lf_min, lf_max, p, 0, q))
+               {  case 0:
+                     /* no logical relation */
+                     break;
+                  case 1:
+                     /* x[p] = 0 implies x[q] = 0 */
+                     lpx_add_cog_edge(cog, -ind[p], +ind[q]);
+                     break;
+                  case 2:
+                     /* x[p] = 0 implies x[q] = 1 */
+                     lpx_add_cog_edge(cog, -ind[p], -ind[q]);
+                     break;
+                  default:
+                     xassert(lp != lp);
+               }
+               /* set x[p] to 1 and examine x[q] */
+               switch (probing(len, val, L, U, lf_min, lf_max, p, 1, q))
+               {  case 0:
+                     /* no logical relation */
+                     break;
+                  case 1:
+                     /* x[p] = 1 implies x[q] = 0 */
+                     lpx_add_cog_edge(cog, +ind[p], +ind[q]);
+                     break;
+                  case 2:
+                     /* x[p] = 1 implies x[q] = 1 */
+                     lpx_add_cog_edge(cog, +ind[p], -ind[q]);
+                     break;
+                  default:
+                     xassert(lp != lp);
+               }
+            }
+         }
+      }
+      xprintf("The conflict graph has 2*%d vertices and %d edges\n",
+         cog->nb, cog->ne);
+done: xfree(ind);
+      xfree(val);
+      return cog;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_add_cog_edge - add edge to the conflict graph.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- void lpx_add_cog_edge(void *cog, int i, int j);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_add_cog_edge adds an edge to the conflict graph.
+-- The edge connects x[i] (if i > 0) or its complement (if i < 0) and
+-- x[j] (if j > 0) or its complement (if j < 0), where i and j are
+-- original ordinal numbers of corresponding variables. */
+
+static void lpx_add_cog_edge(void *_cog, int i, int j)
+{     struct COG *cog = _cog;
+      int k;
+      xassert(i != j);
+      /* determine indices of corresponding vertices */
+      if (i > 0)
+      {  xassert(1 <= i && i <= cog->n);
+         i = cog->vert[i];
+         xassert(i != 0);
+      }
+      else
+      {  i = -i;
+         xassert(1 <= i && i <= cog->n);
+         i = cog->vert[i];
+         xassert(i != 0);
+         i += cog->nb;
+      }
+      if (j > 0)
+      {  xassert(1 <= j && j <= cog->n);
+         j = cog->vert[j];
+         xassert(j != 0);
+      }
+      else
+      {  j = -j;
+         xassert(1 <= j && j <= cog->n);
+         j = cog->vert[j];
+         xassert(j != 0);
+         j += cog->nb;
+      }
+      /* only lower triangle is stored, so we need i > j */
+      if (i < j) k = i, i = j, j = k;
+      k = ((i - 1) * (i - 2)) / 2 + (j - 1);
+      cog->a[k / CHAR_BIT] |=
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+      cog->ne++;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- MAXIMUM WEIGHT CLIQUE
+--
+-- Two subroutines sub() and wclique() below are intended to find a
+-- maximum weight clique in a given undirected graph. These subroutines
+-- are slightly modified version of the program WCLIQUE developed by
+-- Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
+-- on ideas from the article "P. R. J. Ostergard, A new algorithm for
+-- the maximum-weight clique problem, submitted for publication", which
+-- in turn is a generalization of the algorithm for unweighted graphs
+-- presented in "P. R. J. Ostergard, A fast algorithm for the maximum
+-- clique problem, submitted for publication".
+--
+-- USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE. */
+
+struct dsa
+{     /* dynamic storage area */
+      int n;
+      /* number of vertices */
+      int *wt; /* int wt[0:n-1]; */
+      /* weights */
+      unsigned char *a;
+      /* adjacency matrix (packed lower triangle without main diag.) */
+      int record;
+      /* weight of best clique */
+      int rec_level;
+      /* number of vertices in best clique */
+      int *rec; /* int rec[0:n-1]; */
+      /* best clique so far */
+      int *clique; /* int clique[0:n-1]; */
+      /* table for pruning */
+      int *set; /* int set[0:n-1]; */
+      /* current clique */
+};
+
+#define n         (dsa->n)
+#define wt        (dsa->wt)
+#define a         (dsa->a)
+#define record    (dsa->record)
+#define rec_level (dsa->rec_level)
+#define rec       (dsa->rec)
+#define clique    (dsa->clique)
+#define set       (dsa->set)
+
+#if 0
+static int is_edge(struct dsa *dsa, int i, int j)
+{     /* if there is arc (i,j), the routine returns true; otherwise
+         false; 0 <= i, j < n */
+      int k;
+      xassert(0 <= i && i < n);
+      xassert(0 <= j && j < n);
+      if (i == j) return 0;
+      if (i < j) k = i, i = j, j = k;
+      k = (i * (i - 1)) / 2 + j;
+      return a[k / CHAR_BIT] &
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+}
+#else
+#define is_edge(dsa, i, j) ((i) == (j) ? 0 : \
+      (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
+#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
+#define is_edge2(k) (a[(k) / CHAR_BIT] & \
+      (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
+#endif
+
+static void sub(struct dsa *dsa, int ct, int table[], int level,
+      int weight, int l_weight)
+{     int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
+      newtable = xcalloc(n, sizeof(int));
+      if (ct <= 0)
+      {  /* 0 or 1 elements left; include these */
+         if (ct == 0)
+         {  set[level++] = table[0];
+            weight += l_weight;
+         }
+         if (weight > record)
+         {  record = weight;
+            rec_level = level;
+            for (i = 0; i < level; i++) rec[i] = set[i];
+         }
+         goto done;
+      }
+      for (i = ct; i >= 0; i--)
+      {  if ((level == 0) && (i < ct)) goto done;
+         k = table[i];
+         if ((level > 0) && (clique[k] <= (record - weight)))
+            goto done; /* prune */
+         set[level] = k;
+         curr_weight = weight + wt[k];
+         l_weight -= wt[k];
+         if (l_weight <= (record - curr_weight))
+            goto done; /* prune */
+         p1 = newtable;
+         p2 = table;
+         left_weight = 0;
+         while (p2 < table + i)
+         {  j = *p2++;
+            if (is_edge(dsa, j, k))
+            {  *p1++ = j;
+               left_weight += wt[j];
+            }
+         }
+         if (left_weight <= (record - curr_weight)) continue;
+         sub(dsa, p1 - newtable - 1, newtable, level + 1, curr_weight,
+            left_weight);
+      }
+done: xfree(newtable);
+      return;
+}
+
+static int wclique(int _n, int w[], unsigned char _a[], int sol[])
+{     struct dsa _dsa, *dsa = &_dsa;
+      int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
+      glp_long timer;
+      n = _n;
+      wt = &w[1];
+      a = _a;
+      record = 0;
+      rec_level = 0;
+      rec = &sol[1];
+      clique = xcalloc(n, sizeof(int));
+      set = xcalloc(n, sizeof(int));
+      used = xcalloc(n, sizeof(int));
+      nwt = xcalloc(n, sizeof(int));
+      pos = xcalloc(n, sizeof(int));
+      /* start timer */
+      timer = xtime();
+      /* order vertices */
+      for (i = 0; i < n; i++)
+      {  nwt[i] = 0;
+         for (j = 0; j < n; j++)
+            if (is_edge(dsa, i, j)) nwt[i] += wt[j];
+      }
+      for (i = 0; i < n; i++)
+         used[i] = 0;
+      for (i = n-1; i >= 0; i--)
+      {  max_wt = -1;
+         max_nwt = -1;
+         for (j = 0; j < n; j++)
+         {  if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
+               && nwt[j] > max_nwt)))
+            {  max_wt = wt[j];
+               max_nwt = nwt[j];
+               p = j;
+            }
+         }
+         pos[i] = p;
+         used[p] = 1;
+         for (j = 0; j < n; j++)
+            if ((!used[j]) && (j != p) && (is_edge(dsa, p, j)))
+               nwt[j] -= wt[p];
+      }
+      /* main routine */
+      wth = 0;
+      for (i = 0; i < n; i++)
+      {  wth += wt[pos[i]];
+         sub(dsa, i, pos, 0, 0, wth);
+         clique[pos[i]] = record;
+#if 0
+         if (utime() >= timer + 5.0)
+#else
+         if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
+#endif
+         {  /* print current record and reset timer */
+            xprintf("level = %d (%d); best = %d\n", i+1, n, record);
+#if 0
+            timer = utime();
+#else
+            timer = xtime();
+#endif
+         }
+      }
+      xfree(clique);
+      xfree(set);
+      xfree(used);
+      xfree(nwt);
+      xfree(pos);
+      /* return the solution found */
+      for (i = 1; i <= rec_level; i++) sol[i]++;
+      return rec_level;
+}
+
+#undef n
+#undef wt
+#undef a
+#undef record
+#undef rec_level
+#undef rec
+#undef clique
+#undef set
+
+/*----------------------------------------------------------------------
+-- lpx_clique_cut - generate cluque cut.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- int lpx_clique_cut(LPX *lp, void *cog, int ind[], double val[]);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_clique_cut generates a clique cut using the conflict
+-- graph specified by the parameter cog.
+--
+-- If a violated clique cut has been found, it has the following form:
+--
+--    sum{j in J} a[j]*x[j] <= b.
+--
+-- Variable indices j in J are stored in elements ind[1], ..., ind[len]
+-- while corresponding constraint coefficients are stored in elements
+-- val[1], ..., val[len], where len is returned on exit. The right-hand
+-- side b is stored in element val[0].
+--
+-- RETURNS
+--
+-- If the cutting plane has been successfully generated, the routine
+-- returns 1 <= len <= n, which is the number of non-zero coefficients
+-- in the inequality constraint. Otherwise, the routine returns zero. */
+
+static int lpx_clique_cut(LPX *lp, void *_cog, int ind[], double val[])
+{     struct COG *cog = _cog;
+      int n = lpx_get_num_cols(lp);
+      int j, t, v, card, temp, len = 0, *w, *sol;
+      double x, sum, b, *vec;
+      /* allocate working arrays */
+      w = xcalloc(1 + 2 * cog->nb, sizeof(int));
+      sol = xcalloc(1 + 2 * cog->nb, sizeof(int));
+      vec = xcalloc(1+n, sizeof(double));
+      /* assign weights to vertices of the conflict graph */
+      for (t = 1; t <= cog->nb; t++)
+      {  j = cog->orig[t];
+         x = lpx_get_col_prim(lp, j);
+         temp = (int)(100.0 * x + 0.5);
+         if (temp < 0) temp = 0;
+         if (temp > 100) temp = 100;
+         w[t] = temp;
+         w[cog->nb + t] = 100 - temp;
+      }
+      /* find a clique of maximum weight */
+      card = wclique(2 * cog->nb, w, cog->a, sol);
+      /* compute the clique weight for unscaled values */
+      sum = 0.0;
+      for ( t = 1; t <= card; t++)
+      {  v = sol[t];
+         xassert(1 <= v && v <= 2 * cog->nb);
+         if (v <= cog->nb)
+         {  /* vertex v corresponds to binary variable x[j] */
+            j = cog->orig[v];
+            x = lpx_get_col_prim(lp, j);
+            sum += x;
+         }
+         else
+         {  /* vertex v corresponds to the complement of x[j] */
+            j = cog->orig[v - cog->nb];
+            x = lpx_get_col_prim(lp, j);
+            sum += 1.0 - x;
+         }
+      }
+      /* if the sum of binary variables and their complements in the
+         clique greater than 1, the clique cut is violated */
+      if (sum >= 1.01)
+      {  /* construct the inquality */
+         for (j = 1; j <= n; j++) vec[j] = 0;
+         b = 1.0;
+         for (t = 1; t <= card; t++)
+         {  v = sol[t];
+            if (v <= cog->nb)
+            {  /* vertex v corresponds to binary variable x[j] */
+               j = cog->orig[v];
+               xassert(1 <= j && j <= n);
+               vec[j] += 1.0;
+            }
+            else
+            {  /* vertex v corresponds to the complement of x[j] */
+               j = cog->orig[v - cog->nb];
+               xassert(1 <= j && j <= n);
+               vec[j] -= 1.0;
+               b -= 1.0;
+            }
+         }
+         xassert(len == 0);
+         for (j = 1; j <= n; j++)
+         {  if (vec[j] != 0.0)
+            {  len++;
+               ind[len] = j, val[len] = vec[j];
+            }
+         }
+         ind[0] = 0, val[0] = b;
+      }
+      /* free working arrays */
+      xfree(w);
+      xfree(sol);
+      xfree(vec);
+      /* return to the calling program */
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_delete_cog - delete the conflict graph.
+--
+-- SYNOPSIS
+--
+-- #include "glplpx.h"
+-- void lpx_delete_cog(void *cog);
+--
+-- DESCRIPTION
+--
+-- The routine lpx_delete_cog deletes the conflict graph, which the
+-- parameter cog points to, freeing all the memory allocated to this
+-- object. */
+
+static void lpx_delete_cog(void *_cog)
+{     struct COG *cog = _cog;
+      xfree(cog->vert);
+      xfree(cog->orig);
+      xfree(cog->a);
+      xfree(cog);
+}
+
+/**********************************************************************/
+
+void *ios_clq_init(glp_tree *tree)
+{     /* initialize clique cut generator */
+      glp_prob *mip = tree->mip;
+      xassert(mip != NULL);
+      return lpx_create_cog(mip);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ios_clq_gen - generate clique cuts
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_clq_gen(glp_tree *tree, void *gen);
+*
+*  DESCRIPTION
+*
+*  The routine ios_clq_gen generates clique cuts for the current point
+*  and adds them to the clique pool. */
+
+void ios_clq_gen(glp_tree *tree, void *gen)
+{     int n = lpx_get_num_cols(tree->mip);
+      int len, *ind;
+      double *val;
+      xassert(gen != NULL);
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      len = lpx_clique_cut(tree->mip, gen, ind, val);
+      if (len > 0)
+      {  /* xprintf("len = %d\n", len); */
+         glp_ios_add_row(tree, NULL, GLP_RF_CLQ, 0, len, ind, val,
+            GLP_UP, val[0]);
+      }
+      xfree(ind);
+      xfree(val);
+      return;
+}
+
+/**********************************************************************/
+
+void ios_clq_term(void *gen)
+{     /* terminate clique cut generator */
+      xassert(gen != NULL);
+      lpx_delete_cog(gen);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpios09.c
===================================================================
--- deps/glpk/src/glpios09.c	(revision 9)
+++ deps/glpk/src/glpios09.c	(revision 9)
@@ -0,0 +1,659 @@
+/* glpios09.c (branching heuristics) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_choose_var - select variable to branch on
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_choose_var(glp_tree *T, int *next);
+*
+*  The routine ios_choose_var chooses a variable from the candidate
+*  list to branch on. Additionally the routine provides a flag stored
+*  in the location next to suggests which of the child subproblems
+*  should be solved next.
+*
+*  RETURNS
+*
+*  The routine ios_choose_var returns the ordinal number of the column
+*  choosen. */
+
+static int branch_first(glp_tree *T, int *next);
+static int branch_last(glp_tree *T, int *next);
+static int branch_mostf(glp_tree *T, int *next);
+static int branch_drtom(glp_tree *T, int *next);
+
+int ios_choose_var(glp_tree *T, int *next)
+{     int j;
+      if (T->parm->br_tech == GLP_BR_FFV)
+      {  /* branch on first fractional variable */
+         j = branch_first(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_LFV)
+      {  /* branch on last fractional variable */
+         j = branch_last(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_MFV)
+      {  /* branch on most fractional variable */
+         j = branch_mostf(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_DTH)
+      {  /* branch using the heuristic by Dreebeck and Tomlin */
+         j = branch_drtom(T, next);
+      }
+      else if (T->parm->br_tech == GLP_BR_PCH)
+      {  /* hybrid pseudocost heuristic */
+         j = ios_pcost_branch(T, next);
+      }
+      else
+         xassert(T != T);
+      return j;
+}
+
+/***********************************************************************
+*  branch_first - choose first branching variable
+*
+*  This routine looks up the list of structural variables and chooses
+*  the first one, which is of integer kind and has fractional value in
+*  optimal solution to the current LP relaxation.
+*
+*  This routine also selects the branch to be solved next where integer
+*  infeasibility of the chosen variable is less than in other one. */
+
+static int branch_first(glp_tree *T, int *_next)
+{     int j, next;
+      double beta;
+      /* choose the column to branch on */
+      for (j = 1; j <= T->n; j++)
+         if (T->non_int[j]) break;
+      xassert(1 <= j && j <= T->n);
+      /* select the branch to be solved next */
+      beta = glp_get_col_prim(T->mip, j);
+      if (beta - floor(beta) < ceil(beta) - beta)
+         next = GLP_DN_BRNCH;
+      else
+         next = GLP_UP_BRNCH;
+      *_next = next;
+      return j;
+}
+
+/***********************************************************************
+*  branch_last - choose last branching variable
+*
+*  This routine looks up the list of structural variables and chooses
+*  the last one, which is of integer kind and has fractional value in
+*  optimal solution to the current LP relaxation.
+*
+*  This routine also selects the branch to be solved next where integer
+*  infeasibility of the chosen variable is less than in other one. */
+
+static int branch_last(glp_tree *T, int *_next)
+{     int j, next;
+      double beta;
+      /* choose the column to branch on */
+      for (j = T->n; j >= 1; j--)
+         if (T->non_int[j]) break;
+      xassert(1 <= j && j <= T->n);
+      /* select the branch to be solved next */
+      beta = glp_get_col_prim(T->mip, j);
+      if (beta - floor(beta) < ceil(beta) - beta)
+         next = GLP_DN_BRNCH;
+      else
+         next = GLP_UP_BRNCH;
+      *_next = next;
+      return j;
+}
+
+/***********************************************************************
+*  branch_mostf - choose most fractional branching variable
+*
+*  This routine looks up the list of structural variables and chooses
+*  that one, which is of integer kind and has most fractional value in
+*  optimal solution to the current LP relaxation.
+*
+*  This routine also selects the branch to be solved next where integer
+*  infeasibility of the chosen variable is less than in other one.
+*
+*  (Alexander Martin notices that "...most infeasible is as good as
+*  random...".) */
+
+static int branch_mostf(glp_tree *T, int *_next)
+{     int j, jj, next;
+      double beta, most, temp;
+      /* choose the column to branch on */
+      jj = 0, most = DBL_MAX;
+      for (j = 1; j <= T->n; j++)
+      {  if (T->non_int[j])
+         {  beta = glp_get_col_prim(T->mip, j);
+            temp = floor(beta) + 0.5;
+            if (most > fabs(beta - temp))
+            {  jj = j, most = fabs(beta - temp);
+               if (beta < temp)
+                  next = GLP_DN_BRNCH;
+               else
+                  next = GLP_UP_BRNCH;
+            }
+         }
+      }
+      *_next = next;
+      return jj;
+}
+
+/***********************************************************************
+*  branch_drtom - choose branching var using Driebeck-Tomlin heuristic
+*
+*  This routine chooses a structural variable, which is required to be
+*  integral and has fractional value in optimal solution of the current
+*  LP relaxation, using a heuristic proposed by Driebeck and Tomlin.
+*
+*  The routine also selects the branch to be solved next, again due to
+*  Driebeck and Tomlin.
+*
+*  This routine is based on the heuristic proposed in:
+*
+*  Driebeck N.J. An algorithm for the solution of mixed-integer
+*  programming problems, Management Science, 12: 576-87 (1966);
+*
+*  and improved in:
+*
+*  Tomlin J.A. Branch and bound methods for integer and non-convex
+*  programming, in J.Abadie (ed.), Integer and Nonlinear Programming,
+*  North-Holland, Amsterdam, pp. 437-50 (1970).
+*
+*  Must note that this heuristic is time-expensive, because computing
+*  one-step degradation (see the routine below) requires one BTRAN for
+*  each fractional-valued structural variable. */
+
+static int branch_drtom(glp_tree *T, int *_next)
+{     glp_prob *mip = T->mip;
+      int m = mip->m;
+      int n = mip->n;
+      char *non_int = T->non_int;
+      int j, jj, k, t, next, kase, len, stat, *ind;
+      double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up,
+         dd_dn, dd_up, degrad, *val;
+      /* basic solution of LP relaxation must be optimal */
+      xassert(glp_get_status(mip) == GLP_OPT);
+      /* allocate working arrays */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+      /* nothing has been chosen so far */
+      jj = 0, degrad = -1.0;
+      /* walk through the list of columns (structural variables) */
+      for (j = 1; j <= n; j++)
+      {  /* if j-th column is not marked as fractional, skip it */
+         if (!non_int[j]) continue;
+         /* obtain (fractional) value of j-th column in basic solution
+            of LP relaxation */
+         x = glp_get_col_prim(mip, j);
+         /* since the value of j-th column is fractional, the column is
+            basic; compute corresponding row of the simplex table */
+         len = glp_eval_tab_row(mip, m+j, ind, val);
+         /* the following fragment computes a change in the objective
+            function: delta Z = new Z - old Z, where old Z is the
+            objective value in the current optimal basis, and new Z is
+            the objective value in the adjacent basis, for two cases:
+            1) if new upper bound ub' = floor(x[j]) is introduced for
+               j-th column (down branch);
+            2) if new lower bound lb' = ceil(x[j]) is introduced for
+               j-th column (up branch);
+            since in both cases the solution remaining dual feasible
+            becomes primal infeasible, one implicit simplex iteration
+            is performed to determine the change delta Z;
+            it is obvious that new Z, which is never better than old Z,
+            is a lower (minimization) or upper (maximization) bound of
+            the objective function for down- and up-branches. */
+         for (kase = -1; kase <= +1; kase += 2)
+         {  /* if kase < 0, the new upper bound of x[j] is introduced;
+               in this case x[j] should decrease in order to leave the
+               basis and go to its new upper bound */
+            /* if kase > 0, the new lower bound of x[j] is introduced;
+               in this case x[j] should increase in order to leave the
+               basis and go to its new lower bound */
+            /* apply the dual ratio test in order to determine which
+               auxiliary or structural variable should enter the basis
+               to keep dual feasibility */
+            k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9);
+            if (k != 0) k = ind[k];
+            /* if no non-basic variable has been chosen, LP relaxation
+               of corresponding branch being primal infeasible and dual
+               unbounded has no primal feasible solution; in this case
+               the change delta Z is formally set to infinity */
+            if (k == 0)
+            {  delta_z =
+                  (T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX);
+               goto skip;
+            }
+            /* row of the simplex table that corresponds to non-basic
+               variable x[k] choosen by the dual ratio test is:
+                  x[j] = ... + alfa * x[k] + ...
+               where alfa is the influence coefficient (an element of
+               the simplex table row) */
+            /* determine the coefficient alfa */
+            for (t = 1; t <= len; t++) if (ind[t] == k) break;
+            xassert(1 <= t && t <= len);
+            alfa = val[t];
+            /* since in the adjacent basis the variable x[j] becomes
+               non-basic, knowing its value in the current basis we can
+               determine its change delta x[j] = new x[j] - old x[j] */
+            delta_j = (kase < 0 ? floor(x) : ceil(x)) - x;
+            /* and knowing the coefficient alfa we can determine the
+               corresponding change delta x[k] = new x[k] - old x[k],
+               where old x[k] is a value of x[k] in the current basis,
+               and new x[k] is a value of x[k] in the adjacent basis */
+            delta_k = delta_j / alfa;
+            /* Tomlin noticed that if the variable x[k] is of integer
+               kind, its change cannot be less (eventually) than one in
+               the magnitude */
+            if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV)
+            {  /* x[k] is structural integer variable */
+               if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3)
+               {  if (delta_k > 0.0)
+                     delta_k = ceil(delta_k);  /* +3.14 -> +4 */
+                  else
+                     delta_k = floor(delta_k); /* -3.14 -> -4 */
+               }
+            }
+            /* now determine the status and reduced cost of x[k] in the
+               current basis */
+            if (k <= m)
+            {  stat = glp_get_row_stat(mip, k);
+               dk = glp_get_row_dual(mip, k);
+            }
+            else
+            {  stat = glp_get_col_stat(mip, k-m);
+               dk = glp_get_col_dual(mip, k-m);
+            }
+            /* if the current basis is dual degenerate, some reduced
+               costs which are close to zero may have wrong sign due to
+               round-off errors, so correct the sign of d[k] */
+            switch (T->mip->dir)
+            {  case GLP_MIN:
+                  if (stat == GLP_NL && dk < 0.0 ||
+                      stat == GLP_NU && dk > 0.0 ||
+                      stat == GLP_NF) dk = 0.0;
+                  break;
+               case GLP_MAX:
+                  if (stat == GLP_NL && dk > 0.0 ||
+                      stat == GLP_NU && dk < 0.0 ||
+                      stat == GLP_NF) dk = 0.0;
+                  break;
+               default:
+                  xassert(T != T);
+            }
+            /* now knowing the change of x[k] and its reduced cost d[k]
+               we can compute the corresponding change in the objective
+               function delta Z = new Z - old Z = d[k] * delta x[k];
+               note that due to Tomlin's modification new Z can be even
+               worse than in the adjacent basis */
+            delta_z = dk * delta_k;
+skip:       /* new Z is never better than old Z, therefore the change
+               delta Z is always non-negative (in case of minimization)
+               or non-positive (in case of maximization) */
+            switch (T->mip->dir)
+            {  case GLP_MIN: xassert(delta_z >= 0.0); break;
+               case GLP_MAX: xassert(delta_z <= 0.0); break;
+               default: xassert(T != T);
+            }
+            /* save the change in the objective fnction for down- and
+               up-branches, respectively */
+            if (kase < 0) dz_dn = delta_z; else dz_up = delta_z;
+         }
+         /* thus, in down-branch no integer feasible solution can be
+            better than Z + dz_dn, and in up-branch no integer feasible
+            solution can be better than Z + dz_up, where Z is value of
+            the objective function in the current basis */
+         /* following the heuristic by Driebeck and Tomlin we choose a
+            column (i.e. structural variable) which provides largest
+            degradation of the objective function in some of branches;
+            besides, we select the branch with smaller degradation to
+            be solved next and keep other branch with larger degradation
+            in the active list hoping to minimize the number of further
+            backtrackings */
+         if (degrad < fabs(dz_dn) || degrad < fabs(dz_up))
+         {  jj = j;
+            if (fabs(dz_dn) < fabs(dz_up))
+            {  /* select down branch to be solved next */
+               next = GLP_DN_BRNCH;
+               degrad = fabs(dz_up);
+            }
+            else
+            {  /* select up branch to be solved next */
+               next = GLP_UP_BRNCH;
+               degrad = fabs(dz_dn);
+            }
+            /* save the objective changes for printing */
+            dd_dn = dz_dn, dd_up = dz_up;
+            /* if down- or up-branch has no feasible solution, we does
+               not need to consider other candidates (in principle, the
+               corresponding branch could be pruned right now) */
+            if (degrad == DBL_MAX) break;
+         }
+      }
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      /* something must be chosen */
+      xassert(1 <= jj && jj <= n);
+#if 1 /* 02/XI-2009 */
+      if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val)))
+      {  jj = branch_mostf(T, &next);
+         goto done;
+      }
+#endif
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+      {  xprintf("branch_drtom: column %d chosen to branch on\n", jj);
+         if (fabs(dd_dn) == DBL_MAX)
+            xprintf("branch_drtom: down-branch is infeasible\n");
+         else
+            xprintf("branch_drtom: down-branch bound is %.9e\n",
+               lpx_get_obj_val(mip) + dd_dn);
+         if (fabs(dd_up) == DBL_MAX)
+            xprintf("branch_drtom: up-branch   is infeasible\n");
+         else
+            xprintf("branch_drtom: up-branch   bound is %.9e\n",
+               lpx_get_obj_val(mip) + dd_up);
+      }
+done: *_next = next;
+      return jj;
+}
+
+/**********************************************************************/
+
+struct csa
+{     /* common storage area */
+      int *dn_cnt; /* int dn_cnt[1+n]; */
+      /* dn_cnt[j] is the number of subproblems, whose LP relaxations
+         have been solved and which are down-branches for variable x[j];
+         dn_cnt[j] = 0 means the down pseudocost is uninitialized */
+      double *dn_sum; /* double dn_sum[1+n]; */
+      /* dn_sum[j] is the sum of per unit degradations of the objective
+         over all dn_cnt[j] subproblems */
+      int *up_cnt; /* int up_cnt[1+n]; */
+      /* up_cnt[j] is the number of subproblems, whose LP relaxations
+         have been solved and which are up-branches for variable x[j];
+         up_cnt[j] = 0 means the up pseudocost is uninitialized */
+      double *up_sum; /* double up_sum[1+n]; */
+      /* up_sum[j] is the sum of per unit degradations of the objective
+         over all up_cnt[j] subproblems */
+};
+
+void *ios_pcost_init(glp_tree *tree)
+{     /* initialize working data used on pseudocost branching */
+      struct csa *csa;
+      int n = tree->n, j;
+      csa = xmalloc(sizeof(struct csa));
+      csa->dn_cnt = xcalloc(1+n, sizeof(int));
+      csa->dn_sum = xcalloc(1+n, sizeof(double));
+      csa->up_cnt = xcalloc(1+n, sizeof(int));
+      csa->up_sum = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  csa->dn_cnt[j] = csa->up_cnt[j] = 0;
+         csa->dn_sum[j] = csa->up_sum[j] = 0.0;
+      }
+      return csa;
+}
+
+static double eval_degrad(glp_prob *P, int j, double bnd)
+{     /* compute degradation of the objective on fixing x[j] at given
+         value with a limited number of dual simplex iterations */
+      /* this routine fixes column x[j] at specified value bnd,
+         solves resulting LP, and returns a lower bound to degradation
+         of the objective, degrad >= 0 */
+      glp_prob *lp;
+      glp_smcp parm;
+      int ret;
+      double degrad;
+      /* the current basis must be optimal */
+      xassert(glp_get_status(P) == GLP_OPT);
+      /* create a copy of P */
+      lp = glp_create_prob();
+      glp_copy_prob(lp, P, 0);
+      /* fix column x[j] at specified value */
+      glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd);
+      /* try to solve resulting LP */
+      glp_init_smcp(&parm);
+      parm.msg_lev = GLP_MSG_OFF;
+      parm.meth = GLP_DUAL;
+      parm.it_lim = 30;
+      parm.out_dly = 1000;
+      parm.meth = GLP_DUAL;
+      ret = glp_simplex(lp, &parm);
+      if (ret == 0 || ret == GLP_EITLIM)
+      {  if (glp_get_prim_stat(lp) == GLP_NOFEAS)
+         {  /* resulting LP has no primal feasible solution */
+            degrad = DBL_MAX;
+         }
+         else if (glp_get_dual_stat(lp) == GLP_FEAS)
+         {  /* resulting basis is optimal or at least dual feasible,
+               so we have the correct lower bound to degradation */
+            if (P->dir == GLP_MIN)
+               degrad = lp->obj_val - P->obj_val;
+            else if (P->dir == GLP_MAX)
+               degrad = P->obj_val - lp->obj_val;
+            else
+               xassert(P != P);
+            /* degradation cannot be negative by definition */
+            /* note that the lower bound to degradation may be close
+               to zero even if its exact value is zero due to round-off
+               errors on computing the objective value */
+            if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val)))
+               degrad = 0.0;
+         }
+         else
+         {  /* the final basis reported by the simplex solver is dual
+               infeasible, so we cannot determine a non-trivial lower
+               bound to degradation */
+            degrad = 0.0;
+         }
+      }
+      else
+      {  /* the simplex solver failed */
+         degrad = 0.0;
+      }
+      /* delete the copy of P */
+      glp_delete_prob(lp);
+      return degrad;
+}
+
+void ios_pcost_update(glp_tree *tree)
+{     /* update history information for pseudocost branching */
+      /* this routine is called every time when LP relaxation of the
+         current subproblem has been solved to optimality with all lazy
+         and cutting plane constraints included */
+      int j;
+      double dx, dz, psi;
+      struct csa *csa = tree->pcost;
+      xassert(csa != NULL);
+      xassert(tree->curr != NULL);
+      /* if the current subproblem is the root, skip updating */
+      if (tree->curr->up == NULL) goto skip;
+      /* determine branching variable x[j], which was used in the
+         parent subproblem to create the current subproblem */
+      j = tree->curr->up->br_var;
+      xassert(1 <= j && j <= tree->n);
+      /* determine the change dx[j] = new x[j] - old x[j],
+         where new x[j] is a value of x[j] in optimal solution to LP
+         relaxation of the current subproblem, old x[j] is a value of
+         x[j] in optimal solution to LP relaxation of the parent
+         subproblem */
+      dx = tree->mip->col[j]->prim - tree->curr->up->br_val;
+      xassert(dx != 0.0);
+      /* determine corresponding change dz = new dz - old dz in the
+         objective function value */
+      dz = tree->mip->obj_val - tree->curr->up->lp_obj;
+      /* determine per unit degradation of the objective function */
+      psi = fabs(dz / dx);
+      /* update history information */
+      if (dx < 0.0)
+      {  /* the current subproblem is down-branch */
+         csa->dn_cnt[j]++;
+         csa->dn_sum[j] += psi;
+      }
+      else /* dx > 0.0 */
+      {  /* the current subproblem is up-branch */
+         csa->up_cnt[j]++;
+         csa->up_sum[j] += psi;
+      }
+skip: return;
+}
+
+void ios_pcost_free(glp_tree *tree)
+{     /* free working area used on pseudocost branching */
+      struct csa *csa = tree->pcost;
+      xassert(csa != NULL);
+      xfree(csa->dn_cnt);
+      xfree(csa->dn_sum);
+      xfree(csa->up_cnt);
+      xfree(csa->up_sum);
+      xfree(csa);
+      tree->pcost = NULL;
+      return;
+}
+
+static double eval_psi(glp_tree *T, int j, int brnch)
+{     /* compute estimation of pseudocost of variable x[j] for down-
+         or up-branch */
+      struct csa *csa = T->pcost;
+      double beta, degrad, psi;
+      xassert(csa != NULL);
+      xassert(1 <= j && j <= T->n);
+      if (brnch == GLP_DN_BRNCH)
+      {  /* down-branch */
+         if (csa->dn_cnt[j] == 0)
+         {  /* initialize down pseudocost */
+            beta = T->mip->col[j]->prim;
+            degrad = eval_degrad(T->mip, j, floor(beta));
+            if (degrad == DBL_MAX)
+            {  psi = DBL_MAX;
+               goto done;
+            }
+            csa->dn_cnt[j] = 1;
+            csa->dn_sum[j] = degrad / (beta - floor(beta));
+         }
+         psi = csa->dn_sum[j] / (double)csa->dn_cnt[j];
+      }
+      else if (brnch == GLP_UP_BRNCH)
+      {  /* up-branch */
+         if (csa->up_cnt[j] == 0)
+         {  /* initialize up pseudocost */
+            beta = T->mip->col[j]->prim;
+            degrad = eval_degrad(T->mip, j, ceil(beta));
+            if (degrad == DBL_MAX)
+            {  psi = DBL_MAX;
+               goto done;
+            }
+            csa->up_cnt[j] = 1;
+            csa->up_sum[j] = degrad / (ceil(beta) - beta);
+         }
+         psi = csa->up_sum[j] / (double)csa->up_cnt[j];
+      }
+      else
+         xassert(brnch != brnch);
+done: return psi;
+}
+
+static void progress(glp_tree *T)
+{     /* display progress of pseudocost initialization */
+      struct csa *csa = T->pcost;
+      int j, nv = 0, ni = 0;
+      for (j = 1; j <= T->n; j++)
+      {  if (glp_ios_can_branch(T, j))
+         {  nv++;
+            if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++;
+         }
+      }
+      xprintf("Pseudocosts initialized for %d of %d variables\n",
+         ni, nv);
+      return;
+}
+
+int ios_pcost_branch(glp_tree *T, int *_next)
+{     /* choose branching variable with pseudocost branching */
+      glp_long t = xtime();
+      int j, jjj, sel;
+      double beta, psi, d1, d2, d, dmax;
+      /* initialize the working arrays */
+      if (T->pcost == NULL)
+         T->pcost = ios_pcost_init(T);
+      /* nothing has been chosen so far */
+      jjj = 0, dmax = -1.0;
+      /* go through the list of branching candidates */
+      for (j = 1; j <= T->n; j++)
+      {  if (!glp_ios_can_branch(T, j)) continue;
+         /* determine primal value of x[j] in optimal solution to LP
+            relaxation of the current subproblem */
+         beta = T->mip->col[j]->prim;
+         /* estimate pseudocost of x[j] for down-branch */
+         psi = eval_psi(T, j, GLP_DN_BRNCH);
+         if (psi == DBL_MAX)
+         {  /* down-branch has no primal feasible solution */
+            jjj = j, sel = GLP_DN_BRNCH;
+            goto done;
+         }
+         /* estimate degradation of the objective for down-branch */
+         d1 = psi * (beta - floor(beta));
+         /* estimate pseudocost of x[j] for up-branch */
+         psi = eval_psi(T, j, GLP_UP_BRNCH);
+         if (psi == DBL_MAX)
+         {  /* up-branch has no primal feasible solution */
+            jjj = j, sel = GLP_UP_BRNCH;
+            goto done;
+         }
+         /* estimate degradation of the objective for up-branch */
+         d2 = psi * (ceil(beta) - beta);
+         /* determine d = max(d1, d2) */
+         d = (d1 > d2 ? d1 : d2);
+         /* choose x[j] which provides maximal estimated degradation of
+            the objective either in down- or up-branch */
+         if (dmax < d)
+         {  dmax = d;
+            jjj = j;
+            /* continue the search from a subproblem, where degradation
+               is less than in other one */
+            sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH);
+         }
+         /* display progress of pseudocost initialization */
+         if (T->parm->msg_lev >= GLP_ON)
+         {  if (xdifftime(xtime(), t) >= 10.0)
+            {  progress(T);
+               t = xtime();
+            }
+         }
+      }
+      if (dmax == 0.0)
+      {  /* no degradation is indicated; choose a variable having most
+            fractional value */
+         jjj = branch_mostf(T, &sel);
+      }
+done: *_next = sel;
+      return jjj;
+}
+
+/* eof */
Index: deps/glpk/src/glpios10.c
===================================================================
--- deps/glpk/src/glpios10.c	(revision 9)
+++ deps/glpk/src/glpios10.c	(revision 9)
@@ -0,0 +1,348 @@
+/* glpios10.c (feasibility pump heuristic) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+#include "glprng.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_feas_pump - feasibility pump heuristic
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_feas_pump(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_feas_pump is a simple implementation of the Feasi-
+*  bility Pump heuristic.
+*
+*  REFERENCES
+*
+*  M.Fischetti, F.Glover, and A.Lodi. "The feasibility pump." Math.
+*  Program., Ser. A 104, pp. 91-104 (2005). */
+
+struct VAR
+{     /* binary variable */
+      int j;
+      /* ordinal number */
+      int x;
+      /* value in the rounded solution (0 or 1) */
+      double d;
+      /* sorting key */
+};
+
+static int fcmp(const void *x, const void *y)
+{     /* comparison routine */
+      const struct VAR *vx = x, *vy = y;
+      if (vx->d > vy->d)
+         return -1;
+      else if (vx->d < vy->d)
+         return +1;
+      else
+         return 0;
+}
+
+void ios_feas_pump(glp_tree *T)
+{     glp_prob *P = T->mip;
+      int n = P->n;
+      glp_prob *lp = NULL;
+      struct VAR *var = NULL;
+      RNG *rand = NULL;
+      GLPCOL *col;
+      glp_smcp parm;
+      int j, k, new_x, nfail, npass, nv, ret, stalling;
+      double dist, tol;
+      xassert(glp_get_status(P) == GLP_OPT);
+      /* this heuristic is applied only once on the root level */
+      if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done;
+      /* determine number of binary variables */
+      nv = 0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         /* if x[j] is continuous, skip it */
+         if (col->kind == GLP_CV) continue;
+         /* if x[j] is fixed, skip it */
+         if (col->type == GLP_FX) continue;
+         /* x[j] is non-fixed integer */
+         xassert(col->kind == GLP_IV);
+         if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
+         {  /* x[j] is binary */
+            nv++;
+         }
+         else
+         {  /* x[j] is general integer */
+            if (T->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("FPUMP heuristic cannot be applied due to genera"
+                  "l integer variables\n");
+            goto done;
+         }
+      }
+      /* there must be at least one binary variable */
+      if (nv == 0) goto done;
+      if (T->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Applying FPUMP heuristic...\n");
+      /* build the list of binary variables */
+      var = xcalloc(1+nv, sizeof(struct VAR));
+      k = 0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         if (col->kind == GLP_IV && col->type == GLP_DB)
+            var[++k].j = j;
+      }
+      xassert(k == nv);
+      /* create working problem object */
+      lp = glp_create_prob();
+more: /* copy the original problem object to keep it intact */
+      glp_copy_prob(lp, P, GLP_OFF);
+      /* we are interested to find an integer feasible solution, which
+         is better than the best known one */
+      if (P->mip_stat == GLP_FEAS)
+      {  int *ind;
+         double *val, bnd;
+         /* add a row and make it identical to the objective row */
+         glp_add_rows(lp, 1);
+         ind = xcalloc(1+n, sizeof(int));
+         val = xcalloc(1+n, sizeof(double));
+         for (j = 1; j <= n; j++)
+         {  ind[j] = j;
+            val[j] = P->col[j]->coef;
+         }
+         glp_set_mat_row(lp, lp->m, n, ind, val);
+         xfree(ind);
+         xfree(val);
+         /* introduce upper (minimization) or lower (maximization)
+            bound to the original objective function; note that this
+            additional constraint is not violated at the optimal point
+            to LP relaxation */
+#if 0 /* modified by xypron <xypron.glpk@gmx.de> */
+         if (P->dir == GLP_MIN)
+         {  bnd = P->mip_obj - 0.10 * (1.0 + fabs(P->mip_obj));
+            if (bnd < P->obj_val) bnd = P->obj_val;
+            glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
+         }
+         else if (P->dir == GLP_MAX)
+         {  bnd = P->mip_obj + 0.10 * (1.0 + fabs(P->mip_obj));
+            if (bnd > P->obj_val) bnd = P->obj_val;
+            glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
+         }
+         else
+            xassert(P != P);
+#else
+         bnd = 0.1 * P->obj_val + 0.9 * P->mip_obj;
+         /* xprintf("bnd = %f\n", bnd); */
+         if (P->dir == GLP_MIN)
+            glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0);
+         else if (P->dir == GLP_MAX)
+            glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0);
+         else
+            xassert(P != P);
+#endif
+      }
+      /* reset pass count */
+      npass = 0;
+      /* invalidate the rounded point */
+      for (k = 1; k <= nv; k++)
+         var[k].x = -1;
+pass: /* next pass starts here */
+      npass++;
+      if (T->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Pass %d\n", npass);
+      /* initialize minimal distance between the basic point and the
+         rounded one obtained during this pass */
+      dist = DBL_MAX;
+      /* reset failure count (the number of succeeded iterations failed
+         to improve the distance) */
+      nfail = 0;
+      /* if it is not the first pass, perturb the last rounded point
+         rather than construct it from the basic solution */
+      if (npass > 1)
+      {  double rho, temp;
+         if (rand == NULL)
+            rand = rng_create_rand();
+         for (k = 1; k <= nv; k++)
+         {  j = var[k].j;
+            col = lp->col[j];
+            rho = rng_uniform(rand, -0.3, 0.7);
+            if (rho < 0.0) rho = 0.0;
+            temp = fabs((double)var[k].x - col->prim);
+            if (temp + rho > 0.5) var[k].x = 1 - var[k].x;
+         }
+         goto skip;
+      }
+loop: /* innermost loop begins here */
+      /* round basic solution (which is assumed primal feasible) */
+      stalling = 1;
+      for (k = 1; k <= nv; k++)
+      {  col = lp->col[var[k].j];
+         if (col->prim < 0.5)
+         {  /* rounded value is 0 */
+            new_x = 0;
+         }
+         else
+         {  /* rounded value is 1 */
+            new_x = 1;
+         }
+         if (var[k].x != new_x)
+         {  stalling = 0;
+            var[k].x = new_x;
+         }
+      }
+      /* if the rounded point has not changed (stalling), choose and
+         flip some its entries heuristically */
+      if (stalling)
+      {  /* compute d[j] = |x[j] - round(x[j])| */
+         for (k = 1; k <= nv; k++)
+         {  col = lp->col[var[k].j];
+            var[k].d = fabs(col->prim - (double)var[k].x);
+         }
+         /* sort the list of binary variables by descending d[j] */
+         qsort(&var[1], nv, sizeof(struct VAR), fcmp);
+         /* choose and flip some rounded components */
+         for (k = 1; k <= nv; k++)
+         {  if (k >= 5 && var[k].d < 0.35 || k >= 10) break;
+            var[k].x = 1 - var[k].x;
+         }
+      }
+skip: /* check if the time limit has been exhausted */
+      if (T->parm->tm_lim < INT_MAX &&
+         (double)(T->parm->tm_lim - 1) <=
+         1000.0 * xdifftime(xtime(), T->tm_beg)) goto done;
+      /* build the objective, which is the distance between the current
+         (basic) point and the rounded one */
+      lp->dir = GLP_MIN;
+      lp->c0 = 0.0;
+      for (j = 1; j <= n; j++)
+         lp->col[j]->coef = 0.0;
+      for (k = 1; k <= nv; k++)
+      {  j = var[k].j;
+         if (var[k].x == 0)
+            lp->col[j]->coef = +1.0;
+         else
+         {  lp->col[j]->coef = -1.0;
+            lp->c0 += 1.0;
+         }
+      }
+      /* minimize the distance with the simplex method */
+      glp_init_smcp(&parm);
+      if (T->parm->msg_lev <= GLP_MSG_ERR)
+         parm.msg_lev = T->parm->msg_lev;
+      else if (T->parm->msg_lev <= GLP_MSG_ALL)
+      {  parm.msg_lev = GLP_MSG_ON;
+         parm.out_dly = 10000;
+      }
+      ret = glp_simplex(lp, &parm);
+      if (ret != 0)
+      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("Warning: glp_simplex returned %d\n", ret);
+         goto done;
+      }
+      ret = glp_get_status(lp);
+      if (ret != GLP_OPT)
+      {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+            xprintf("Warning: glp_get_status returned %d\n", ret);
+         goto done;
+      }
+      if (T->parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("delta = %g\n", lp->obj_val);
+      /* check if the basic solution is integer feasible; note that it
+         may be so even if the minimial distance is positive */
+      tol = 0.3 * T->parm->tol_int;
+      for (k = 1; k <= nv; k++)
+      {  col = lp->col[var[k].j];
+         if (tol < col->prim && col->prim < 1.0 - tol) break;
+      }
+      if (k > nv)
+      {  /* okay; the basic solution seems to be integer feasible */
+         double *x = xcalloc(1+n, sizeof(double));
+         for (j = 1; j <= n; j++)
+         {  x[j] = lp->col[j]->prim;
+            if (P->col[j]->kind == GLP_IV) x[j] = floor(x[j] + 0.5);
+         }
+#if 1 /* modified by xypron <xypron.glpk@gmx.de> */
+         /* reset direction and right-hand side of objective */
+         lp->c0  = P->c0;
+         lp->dir = P->dir;
+         /* fix integer variables */
+         for (k = 1; k <= nv; k++)
+         {  lp->col[var[k].j]->lb   = x[var[k].j];
+            lp->col[var[k].j]->ub   = x[var[k].j];
+            lp->col[var[k].j]->type = GLP_FX;
+         }
+         /* copy original objective function */
+         for (j = 1; j <= n; j++)
+            lp->col[j]->coef = P->col[j]->coef;
+         /* solve original LP and copy result */
+         ret = glp_simplex(lp, &parm);
+         if (ret != 0)
+         {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: glp_simplex returned %d\n", ret);
+            goto done;
+         }
+         ret = glp_get_status(lp);
+         if (ret != GLP_OPT)
+         {  if (T->parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: glp_get_status returned %d\n", ret);
+            goto done;
+         }
+         for (j = 1; j <= n; j++)
+            if (P->col[j]->kind != GLP_IV) x[j] = lp->col[j]->prim;
+#endif
+         ret = glp_ios_heur_sol(T, x);
+         xfree(x);
+         if (ret == 0)
+         {  /* the integer solution is accepted */
+            if (ios_is_hopeful(T, T->curr->bound))
+            {  /* it is reasonable to apply the heuristic once again */
+               goto more;
+            }
+            else
+            {  /* the best known integer feasible solution just found
+                  is close to optimal solution to LP relaxation */
+               goto done;
+            }
+         }
+      }
+      /* the basic solution is fractional */
+      if (dist == DBL_MAX ||
+          lp->obj_val <= dist - 1e-6 * (1.0 + dist))
+      {  /* the distance is reducing */
+         nfail = 0, dist = lp->obj_val;
+      }
+      else
+      {  /* improving the distance failed */
+         nfail++;
+      }
+      if (nfail < 3) goto loop;
+      if (npass < 5) goto pass;
+done: /* delete working objects */
+      if (lp != NULL) glp_delete_prob(lp);
+      if (var != NULL) xfree(var);
+      if (rand != NULL) rng_delete_rand(rand);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpios11.c
===================================================================
--- deps/glpk/src/glpios11.c	(revision 9)
+++ deps/glpk/src/glpios11.c	(revision 9)
@@ -0,0 +1,280 @@
+/* glpios11.c (process cuts stored in the local cut pool) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_process_cuts - process cuts stored in the local cut pool
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  void ios_process_cuts(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_process_cuts analyzes each cut currently stored in
+*  the local cut pool, which must be non-empty, and either adds the cut
+*  to the current subproblem or just discards it. All cuts are assumed
+*  to be locally valid. On exit the local cut pool remains unchanged.
+*
+*  REFERENCES
+*
+*  1. E.Balas, S.Ceria, G.Cornuejols, "Mixed 0-1 Programming by
+*     Lift-and-Project in a Branch-and-Cut Framework", Management Sc.,
+*     42 (1996) 1229-1246.
+*
+*  2. G.Andreello, A.Caprara, and M.Fischetti, "Embedding Cuts in
+*     a Branch&Cut Framework: a Computational Study with {0,1/2}-Cuts",
+*     Preliminary Draft, October 28, 2003, pp.6-8. */
+
+struct info
+{     /* estimated cut efficiency */
+      IOSCUT *cut;
+      /* pointer to cut in the cut pool */
+      char flag;
+      /* if this flag is set, the cut is included into the current
+         subproblem */
+      double eff;
+      /* cut efficacy (normalized residual) */
+      double deg;
+      /* lower bound to objective degradation */
+};
+
+static int fcmp(const void *arg1, const void *arg2)
+{     const struct info *info1 = arg1, *info2 = arg2;
+      if (info1->deg == 0.0 && info2->deg == 0.0)
+      {  if (info1->eff > info2->eff) return -1;
+         if (info1->eff < info2->eff) return +1;
+      }
+      else
+      {  if (info1->deg > info2->deg) return -1;
+         if (info1->deg < info2->deg) return +1;
+      }
+      return 0;
+}
+
+static double parallel(IOSCUT *a, IOSCUT *b, double work[]);
+
+void ios_process_cuts(glp_tree *T)
+{     IOSPOOL *pool;
+      IOSCUT *cut;
+      IOSAIJ *aij;
+      struct info *info;
+      int k, kk, max_cuts, len, ret, *ind;
+      double *val, *work;
+      /* the current subproblem must exist */
+      xassert(T->curr != NULL);
+      /* the pool must exist and be non-empty */
+      pool = T->local;
+      xassert(pool != NULL);
+      xassert(pool->size > 0);
+      /* allocate working arrays */
+      info = xcalloc(1+pool->size, sizeof(struct info));
+      ind = xcalloc(1+T->n, sizeof(int));
+      val = xcalloc(1+T->n, sizeof(double));
+      work = xcalloc(1+T->n, sizeof(double));
+      for (k = 1; k <= T->n; k++) work[k] = 0.0;
+      /* build the list of cuts stored in the cut pool */
+      for (k = 0, cut = pool->head; cut != NULL; cut = cut->next)
+         k++, info[k].cut = cut, info[k].flag = 0;
+      xassert(k == pool->size);
+      /* estimate efficiency of all cuts in the cut pool */
+      for (k = 1; k <= pool->size; k++)
+      {  double temp, dy, dz;
+         cut = info[k].cut;
+         /* build the vector of cut coefficients and compute its
+            Euclidean norm */
+         len = 0; temp = 0.0;
+         for (aij = cut->ptr; aij != NULL; aij = aij->next)
+         {  xassert(1 <= aij->j && aij->j <= T->n);
+            len++, ind[len] = aij->j, val[len] = aij->val;
+            temp += aij->val * aij->val;
+         }
+         if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+         /* transform the cut to express it only through non-basic
+            (auxiliary and structural) variables */
+         len = glp_transform_row(T->mip, len, ind, val);
+         /* determine change in the cut value and in the objective
+            value for the adjacent basis by simulating one step of the
+            dual simplex */
+         ret = _glp_analyze_row(T->mip, len, ind, val, cut->type,
+            cut->rhs, 1e-9, NULL, NULL, NULL, NULL, &dy, &dz);
+         /* determine normalized residual and lower bound to objective
+            degradation */
+         if (ret == 0)
+         {  info[k].eff = fabs(dy) / sqrt(temp);
+            /* if some reduced costs violates (slightly) their zero
+               bounds (i.e. have wrong signs) due to round-off errors,
+               dz also may have wrong sign being close to zero */
+            if (T->mip->dir == GLP_MIN)
+            {  if (dz < 0.0) dz = 0.0;
+               info[k].deg = + dz;
+            }
+            else /* GLP_MAX */
+            {  if (dz > 0.0) dz = 0.0;
+               info[k].deg = - dz;
+            }
+         }
+         else if (ret == 1)
+         {  /* the constraint is not violated at the current point */
+            info[k].eff = info[k].deg = 0.0;
+         }
+         else if (ret == 2)
+         {  /* no dual feasible adjacent basis exists */
+            info[k].eff = 1.0;
+            info[k].deg = DBL_MAX;
+         }
+         else
+            xassert(ret != ret);
+         /* if the degradation is too small, just ignore it */
+         if (info[k].deg < 0.01) info[k].deg = 0.0;
+      }
+      /* sort the list of cuts by decreasing objective degradation and
+         then by decreasing efficacy */
+      qsort(&info[1], pool->size, sizeof(struct info), fcmp);
+      /* only first (most efficient) max_cuts in the list are qualified
+         as candidates to be added to the current subproblem */
+      max_cuts = (T->curr->level == 0 ? 90 : 10);
+      if (max_cuts > pool->size) max_cuts = pool->size;
+      /* add cuts to the current subproblem */
+#if 0
+      xprintf("*** adding cuts ***\n");
+#endif
+      for (k = 1; k <= max_cuts; k++)
+      {  int i, len;
+         /* if this cut seems to be inefficient, skip it */
+         if (info[k].deg < 0.01 && info[k].eff < 0.01) continue;
+         /* if the angle between this cut and every other cut included
+            in the current subproblem is small, skip this cut */
+         for (kk = 1; kk < k; kk++)
+         {  if (info[kk].flag)
+            {  if (parallel(info[k].cut, info[kk].cut, work) > 0.90)
+                  break;
+            }
+         }
+         if (kk < k) continue;
+         /* add this cut to the current subproblem */
+#if 0
+         xprintf("eff = %g; deg = %g\n", info[k].eff, info[k].deg);
+#endif
+         cut = info[k].cut, info[k].flag = 1;
+         i = glp_add_rows(T->mip, 1);
+         if (cut->name != NULL)
+            glp_set_row_name(T->mip, i, cut->name);
+         xassert(T->mip->row[i]->origin == GLP_RF_CUT);
+         T->mip->row[i]->klass = cut->klass;
+         len = 0;
+         for (aij = cut->ptr; aij != NULL; aij = aij->next)
+            len++, ind[len] = aij->j, val[len] = aij->val;
+         glp_set_mat_row(T->mip, i, len, ind, val);
+         xassert(cut->type == GLP_LO || cut->type == GLP_UP);
+         glp_set_row_bnds(T->mip, i, cut->type, cut->rhs, cut->rhs);
+      }
+      /* free working arrays */
+      xfree(info);
+      xfree(ind);
+      xfree(val);
+      xfree(work);
+      return;
+}
+
+#if 0
+/***********************************************************************
+*  Given a cut a * x >= b (<= b) the routine efficacy computes the cut
+*  efficacy as follows:
+*
+*     eff = d * (a * x~ - b) / ||a||,
+*
+*  where d is -1 (in case of '>= b') or +1 (in case of '<= b'), x~ is
+*  the vector of values of structural variables in optimal solution to
+*  LP relaxation of the current subproblem, ||a|| is the Euclidean norm
+*  of the vector of cut coefficients.
+*
+*  If the cut is violated at point x~, the efficacy eff is positive,
+*  and its value is the Euclidean distance between x~ and the cut plane
+*  a * x = b in the space of structural variables.
+*
+*  Following geometrical intuition, it is quite natural to consider
+*  this distance as a first-order measure of the expected efficacy of
+*  the cut: the larger the distance the better the cut [1]. */
+
+static double efficacy(glp_tree *T, IOSCUT *cut)
+{     glp_prob *mip = T->mip;
+      IOSAIJ *aij;
+      double s = 0.0, t = 0.0, temp;
+      for (aij = cut->ptr; aij != NULL; aij = aij->next)
+      {  xassert(1 <= aij->j && aij->j <= mip->n);
+         s += aij->val * mip->col[aij->j]->prim;
+         t += aij->val * aij->val;
+      }
+      temp = sqrt(t);
+      if (temp < DBL_EPSILON) temp = DBL_EPSILON;
+      if (cut->type == GLP_LO)
+         temp = (s >= cut->rhs ? 0.0 : (cut->rhs - s) / temp);
+      else if (cut->type == GLP_UP)
+         temp = (s <= cut->rhs ? 0.0 : (s - cut->rhs) / temp);
+      else
+         xassert(cut != cut);
+      return temp;
+}
+#endif
+
+/***********************************************************************
+*  Given two cuts a1 * x >= b1 (<= b1) and a2 * x >= b2 (<= b2) the
+*  routine parallel computes the cosine of angle between the cut planes
+*  a1 * x = b1 and a2 * x = b2 (which is the acute angle between two
+*  normals to these planes) in the space of structural variables as
+*  follows:
+*
+*     cos phi = (a1' * a2) / (||a1|| * ||a2||),
+*
+*  where (a1' * a2) is a dot product of vectors of cut coefficients,
+*  ||a1|| and ||a2|| are Euclidean norms of vectors a1 and a2.
+*
+*  Note that requirement cos phi = 0 forces the cuts to be orthogonal,
+*  i.e. with disjoint support, while requirement cos phi <= 0.999 means
+*  only avoiding duplicate (parallel) cuts [1]. */
+
+static double parallel(IOSCUT *a, IOSCUT *b, double work[])
+{     IOSAIJ *aij;
+      double s = 0.0, sa = 0.0, sb = 0.0, temp;
+      for (aij = a->ptr; aij != NULL; aij = aij->next)
+      {  work[aij->j] = aij->val;
+         sa += aij->val * aij->val;
+      }
+      for (aij = b->ptr; aij != NULL; aij = aij->next)
+      {  s += work[aij->j] * aij->val;
+         sb += aij->val * aij->val;
+      }
+      for (aij = a->ptr; aij != NULL; aij = aij->next)
+         work[aij->j] = 0.0;
+      temp = sqrt(sa) * sqrt(sb);
+      if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON;
+      return s / temp;
+}
+
+/* eof */
Index: deps/glpk/src/glpios12.c
===================================================================
--- deps/glpk/src/glpios12.c	(revision 9)
+++ deps/glpk/src/glpios12.c	(revision 9)
@@ -0,0 +1,176 @@
+/* glpios12.c (node selection heuristics) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpios.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ios_choose_node - select subproblem to continue the search
+*
+*  SYNOPSIS
+*
+*  #include "glpios.h"
+*  int ios_choose_node(glp_tree *T);
+*
+*  DESCRIPTION
+*
+*  The routine ios_choose_node selects a subproblem from the active
+*  list to continue the search. The choice depends on the backtracking
+*  technique option.
+*
+*  RETURNS
+*
+*  The routine ios_choose_node return the reference number of the
+*  subproblem selected. */
+
+static int most_feas(glp_tree *T);
+static int best_proj(glp_tree *T);
+static int best_node(glp_tree *T);
+
+int ios_choose_node(glp_tree *T)
+{     int p;
+      if (T->parm->bt_tech == GLP_BT_DFS)
+      {  /* depth first search */
+         xassert(T->tail != NULL);
+         p = T->tail->p;
+      }
+      else if (T->parm->bt_tech == GLP_BT_BFS)
+      {  /* breadth first search */
+         xassert(T->head != NULL);
+         p = T->head->p;
+      }
+      else if (T->parm->bt_tech == GLP_BT_BLB)
+      {  /* select node with best local bound */
+         p = best_node(T);
+      }
+      else if (T->parm->bt_tech == GLP_BT_BPH)
+      {  if (T->mip->mip_stat == GLP_UNDEF)
+         {  /* "most integer feasible" subproblem */
+            p = most_feas(T);
+         }
+         else
+         {  /* best projection heuristic */
+            p = best_proj(T);
+         }
+      }
+      else
+         xassert(T != T);
+      return p;
+}
+
+static int most_feas(glp_tree *T)
+{     /* select subproblem whose parent has minimal sum of integer
+         infeasibilities */
+      IOSNPD *node;
+      int p;
+      double best;
+      p = 0, best = DBL_MAX;
+      for (node = T->head; node != NULL; node = node->next)
+      {  xassert(node->up != NULL);
+         if (best > node->up->ii_sum)
+            p = node->p, best = node->up->ii_sum;
+      }
+      return p;
+}
+
+static int best_proj(glp_tree *T)
+{     /* select subproblem using the best projection heuristic */
+      IOSNPD *root, *node;
+      int p;
+      double best, deg, obj;
+      /* the global bound must exist */
+      xassert(T->mip->mip_stat == GLP_FEAS);
+      /* obtain pointer to the root node, which must exist */
+      root = T->slot[1].node;
+      xassert(root != NULL);
+      /* deg estimates degradation of the objective function per unit
+         of the sum of integer infeasibilities */
+      xassert(root->ii_sum > 0.0);
+      deg = (T->mip->mip_obj - root->bound) / root->ii_sum;
+      /* nothing has been selected so far */
+      p = 0, best = DBL_MAX;
+      /* walk through the list of active subproblems */
+      for (node = T->head; node != NULL; node = node->next)
+      {  xassert(node->up != NULL);
+         /* obj estimates optimal objective value if the sum of integer
+            infeasibilities were zero */
+         obj = node->up->bound + deg * node->up->ii_sum;
+         if (T->mip->dir == GLP_MAX) obj = - obj;
+         /* select the subproblem which has the best estimated optimal
+            objective value */
+         if (best > obj) p = node->p, best = obj;
+      }
+      return p;
+}
+
+static int best_node(glp_tree *T)
+{     /* select subproblem with best local bound */
+      IOSNPD *node, *best = NULL;
+      double bound, eps;
+      switch (T->mip->dir)
+      {  case GLP_MIN:
+            bound = +DBL_MAX;
+            for (node = T->head; node != NULL; node = node->next)
+               if (bound > node->bound) bound = node->bound;
+            xassert(bound != +DBL_MAX);
+            eps = 0.001 * (1.0 + fabs(bound));
+            for (node = T->head; node != NULL; node = node->next)
+            {  if (node->bound <= bound + eps)
+               {  xassert(node->up != NULL);
+                  if (best == NULL ||
+#if 1
+                  best->up->ii_sum > node->up->ii_sum) best = node;
+#else
+                  best->lp_obj > node->lp_obj) best = node;
+#endif
+               }
+            }
+            break;
+         case GLP_MAX:
+            bound = -DBL_MAX;
+            for (node = T->head; node != NULL; node = node->next)
+               if (bound < node->bound) bound = node->bound;
+            xassert(bound != -DBL_MAX);
+            eps = 0.001 * (1.0 + fabs(bound));
+            for (node = T->head; node != NULL; node = node->next)
+            {  if (node->bound >= bound - eps)
+               {  xassert(node->up != NULL);
+                  if (best == NULL ||
+#if 1
+                  best->up->ii_sum > node->up->ii_sum) best = node;
+#else
+                  best->lp_obj < node->lp_obj) best = node;
+#endif
+               }
+            }
+            break;
+         default:
+            xassert(T != T);
+      }
+      xassert(best != NULL);
+      return best->p;
+}
+
+/* eof */
Index: deps/glpk/src/glpipm.c
===================================================================
--- deps/glpk/src/glpipm.c	(revision 9)
+++ deps/glpk/src/glpipm.c	(revision 9)
@@ -0,0 +1,1143 @@
+/* glpipm.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpipm.h"
+#include "glpmat.h"
+
+#define ITER_MAX 100
+/* maximal number of iterations */
+
+struct csa
+{     /* common storage area */
+      /*--------------------------------------------------------------*/
+      /* LP data */
+      int m;
+      /* number of rows (equality constraints) */
+      int n;
+      /* number of columns (structural variables) */
+      int *A_ptr; /* int A_ptr[1+m+1]; */
+      int *A_ind; /* int A_ind[A_ptr[m+1]]; */
+      double *A_val; /* double A_val[A_ptr[m+1]]; */
+      /* mxn-matrix A in storage-by-rows format */
+      double *b; /* double b[1+m]; */
+      /* m-vector b of right-hand sides */
+      double *c; /* double c[1+n]; */
+      /* n-vector c of objective coefficients; c[0] is constant term of
+         the objective function */
+      /*--------------------------------------------------------------*/
+      /* LP solution */
+      double *x; /* double x[1+n]; */
+      double *y; /* double y[1+m]; */
+      double *z; /* double z[1+n]; */
+      /* current point in primal-dual space; the best point on exit */
+      /*--------------------------------------------------------------*/
+      /* control parameters */
+      const glp_iptcp *parm;
+      /*--------------------------------------------------------------*/
+      /* working arrays and variables */
+      double *D; /* double D[1+n]; */
+      /* diagonal nxn-matrix D = X*inv(Z), where X = diag(x[j]) and
+         Z = diag(z[j]) */
+      int *P; /* int P[1+m+m]; */
+      /* permutation mxm-matrix P used to minimize fill-in in Cholesky
+         factorization */
+      int *S_ptr; /* int S_ptr[1+m+1]; */
+      int *S_ind; /* int S_ind[S_ptr[m+1]]; */
+      double *S_val; /* double S_val[S_ptr[m+1]]; */
+      double *S_diag; /* double S_diag[1+m]; */
+      /* symmetric mxm-matrix S = P*A*D*A'*P' whose upper triangular
+         part without diagonal elements is stored in S_ptr, S_ind, and
+         S_val in storage-by-rows format, diagonal elements are stored
+         in S_diag */
+      int *U_ptr; /* int U_ptr[1+m+1]; */
+      int *U_ind; /* int U_ind[U_ptr[m+1]]; */
+      double *U_val; /* double U_val[U_ptr[m+1]]; */
+      double *U_diag; /* double U_diag[1+m]; */
+      /* upper triangular mxm-matrix U defining Cholesky factorization
+         S = U'*U; its non-diagonal elements are stored in U_ptr, U_ind,
+         U_val in storage-by-rows format, diagonal elements are stored
+         in U_diag */
+      int iter;
+      /* iteration number (0, 1, 2, ...); iter = 0 corresponds to the
+         initial point */
+      double obj;
+      /* current value of the objective function */
+      double rpi;
+      /* relative primal infeasibility rpi = ||A*x-b||/(1+||b||) */
+      double rdi;
+      /* relative dual infeasibility rdi = ||A'*y+z-c||/(1+||c||) */
+      double gap;
+      /* primal-dual gap = |c'*x-b'*y|/(1+|c'*x|) which is a relative
+         difference between primal and dual objective functions */
+      double phi;
+      /* merit function phi = ||A*x-b||/max(1,||b||) +
+                            + ||A'*y+z-c||/max(1,||c||) +
+                            + |c'*x-b'*y|/max(1,||b||,||c||) */
+      double mu;
+      /* duality measure mu = x'*z/n (used as barrier parameter) */
+      double rmu;
+      /* rmu = max(||A*x-b||,||A'*y+z-c||)/mu */
+      double rmu0;
+      /* the initial value of rmu on iteration 0 */
+      double *phi_min; /* double phi_min[1+ITER_MAX]; */
+      /* phi_min[k] = min(phi[k]), where phi[k] is the value of phi on
+         k-th iteration, 0 <= k <= iter */
+      int best_iter;
+      /* iteration number, on which the value of phi reached its best
+         (minimal) value */
+      double *best_x; /* double best_x[1+n]; */
+      double *best_y; /* double best_y[1+m]; */
+      double *best_z; /* double best_z[1+n]; */
+      /* best point (in the sense of the merit function phi) which has
+         been reached on iteration iter_best */
+      double best_obj;
+      /* objective value at the best point */
+      double *dx_aff; /* double dx_aff[1+n]; */
+      double *dy_aff; /* double dy_aff[1+m]; */
+      double *dz_aff; /* double dz_aff[1+n]; */
+      /* affine scaling direction */
+      double alfa_aff_p, alfa_aff_d;
+      /* maximal primal and dual stepsizes in affine scaling direction,
+         on which x and z are still non-negative */
+      double mu_aff;
+      /* duality measure mu_aff = x_aff'*z_aff/n in the boundary point
+         x_aff' = x+alfa_aff_p*dx_aff, z_aff' = z+alfa_aff_d*dz_aff */
+      double sigma;
+      /* Mehrotra's heuristic parameter (0 <= sigma <= 1) */
+      double *dx_cc; /* double dx_cc[1+n]; */
+      double *dy_cc; /* double dy_cc[1+m]; */
+      double *dz_cc; /* double dz_cc[1+n]; */
+      /* centering corrector direction */
+      double *dx; /* double dx[1+n]; */
+      double *dy; /* double dy[1+m]; */
+      double *dz; /* double dz[1+n]; */
+      /* final combined direction dx = dx_aff+dx_cc, dy = dy_aff+dy_cc,
+         dz = dz_aff+dz_cc */
+      double alfa_max_p;
+      double alfa_max_d;
+      /* maximal primal and dual stepsizes in combined direction, on
+         which x and z are still non-negative */
+};
+
+/***********************************************************************
+*  initialize - allocate and initialize common storage area
+*
+*  This routine allocates and initializes the common storage area (CSA)
+*  used by interior-point method routines. */
+
+static void initialize(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int i;
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Matrix A has %d non-zeros\n", csa->A_ptr[m+1]-1);
+      csa->D = xcalloc(1+n, sizeof(double));
+      /* P := I */
+      csa->P = xcalloc(1+m+m, sizeof(int));
+      for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i;
+      /* S := A*A', symbolically */
+      csa->S_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
+         csa->S_ptr);
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Matrix S = A*A' has %d non-zeros (upper triangle)\n",
+            csa->S_ptr[m+1]-1 + m);
+      /* determine P using specified ordering algorithm */
+      if (csa->parm->ord_alg == GLP_ORD_NONE)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Original ordering is being used\n");
+         for (i = 1; i <= m; i++)
+            csa->P[i] = csa->P[m+i] = i;
+      }
+      else if (csa->parm->ord_alg == GLP_ORD_QMD)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Minimum degree ordering (QMD)...\n");
+         min_degree(m, csa->S_ptr, csa->S_ind, csa->P);
+      }
+      else if (csa->parm->ord_alg == GLP_ORD_AMD)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Approximate minimum degree ordering (AMD)...\n");
+         amd_order1(m, csa->S_ptr, csa->S_ind, csa->P);
+      }
+      else if (csa->parm->ord_alg == GLP_ORD_SYMAMD)
+      {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Approximate minimum degree ordering (SYMAMD)...\n")
+               ;
+         symamd_ord(m, csa->S_ptr, csa->S_ind, csa->P);
+      }
+      else
+         xassert(csa != csa);
+      /* S := P*A*A'*P', symbolically */
+      xfree(csa->S_ind);
+      csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind,
+         csa->S_ptr);
+      csa->S_val = xcalloc(csa->S_ptr[m+1], sizeof(double));
+      csa->S_diag = xcalloc(1+m, sizeof(double));
+      /* compute Cholesky factorization S = U'*U, symbolically */
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Computing Cholesky factorization S = L*L'...\n");
+      csa->U_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->U_ind = chol_symbolic(m, csa->S_ptr, csa->S_ind, csa->U_ptr);
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Matrix L has %d non-zeros\n", csa->U_ptr[m+1]-1 + m);
+      csa->U_val = xcalloc(csa->U_ptr[m+1], sizeof(double));
+      csa->U_diag = xcalloc(1+m, sizeof(double));
+      csa->iter = 0;
+      csa->obj = 0.0;
+      csa->rpi = 0.0;
+      csa->rdi = 0.0;
+      csa->gap = 0.0;
+      csa->phi = 0.0;
+      csa->mu = 0.0;
+      csa->rmu = 0.0;
+      csa->rmu0 = 0.0;
+      csa->phi_min = xcalloc(1+ITER_MAX, sizeof(double));
+      csa->best_iter = 0;
+      csa->best_x = xcalloc(1+n, sizeof(double));
+      csa->best_y = xcalloc(1+m, sizeof(double));
+      csa->best_z = xcalloc(1+n, sizeof(double));
+      csa->best_obj = 0.0;
+      csa->dx_aff = xcalloc(1+n, sizeof(double));
+      csa->dy_aff = xcalloc(1+m, sizeof(double));
+      csa->dz_aff = xcalloc(1+n, sizeof(double));
+      csa->alfa_aff_p = 0.0;
+      csa->alfa_aff_d = 0.0;
+      csa->mu_aff = 0.0;
+      csa->sigma = 0.0;
+      csa->dx_cc = xcalloc(1+n, sizeof(double));
+      csa->dy_cc = xcalloc(1+m, sizeof(double));
+      csa->dz_cc = xcalloc(1+n, sizeof(double));
+      csa->dx = csa->dx_aff;
+      csa->dy = csa->dy_aff;
+      csa->dz = csa->dz_aff;
+      csa->alfa_max_p = 0.0;
+      csa->alfa_max_d = 0.0;
+      return;
+}
+
+/***********************************************************************
+*  A_by_vec - compute y = A*x
+*
+*  This routine computes matrix-vector product y = A*x, where A is the
+*  constraint matrix. */
+
+static void A_by_vec(struct csa *csa, double x[], double y[])
+{     /* compute y = A*x */
+      int m = csa->m;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int i, t, beg, end;
+      double temp;
+      for (i = 1; i <= m; i++)
+      {  temp = 0.0;
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++) temp += A_val[t] * x[A_ind[t]];
+         y[i] = temp;
+      }
+      return;
+}
+
+/***********************************************************************
+*  AT_by_vec - compute y = A'*x
+*
+*  This routine computes matrix-vector product y = A'*x, where A' is a
+*  matrix transposed to the constraint matrix A. */
+
+static void AT_by_vec(struct csa *csa, double x[], double y[])
+{     /* compute y = A'*x, where A' is transposed to A */
+      int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int i, j, t, beg, end;
+      double temp;
+      for (j = 1; j <= n; j++) y[j] = 0.0;
+      for (i = 1; i <= m; i++)
+      {  temp = x[i];
+         if (temp == 0.0) continue;
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++) y[A_ind[t]] += A_val[t] * temp;
+      }
+      return;
+}
+
+/***********************************************************************
+*  decomp_NE - numeric factorization of matrix S = P*A*D*A'*P'
+*
+*  This routine implements numeric phase of Cholesky factorization of
+*  the matrix S = P*A*D*A'*P', which is a permuted matrix of the normal
+*  equation system. Matrix D is assumed to be already computed. */
+
+static void decomp_NE(struct csa *csa)
+{     adat_numeric(csa->m, csa->n, csa->P, csa->A_ptr, csa->A_ind,
+         csa->A_val, csa->D, csa->S_ptr, csa->S_ind, csa->S_val,
+         csa->S_diag);
+      chol_numeric(csa->m, csa->S_ptr, csa->S_ind, csa->S_val,
+         csa->S_diag, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag);
+      return;
+}
+
+/***********************************************************************
+*  solve_NE - solve normal equation system
+*
+*  This routine solves the normal equation system:
+*
+*     A*D*A'*y = h.
+*
+*  It is assumed that the matrix A*D*A' has been previously factorized
+*  by the routine decomp_NE.
+*
+*  On entry the array y contains the vector of right-hand sides h. On
+*  exit this array contains the computed vector of unknowns y.
+*
+*  Once the vector y has been computed the routine checks for numeric
+*  stability. If the residual vector:
+*
+*     r = A*D*A'*y - h
+*
+*  is relatively small, the routine returns zero, otherwise non-zero is
+*  returned. */
+
+static int solve_NE(struct csa *csa, double y[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *P = csa->P;
+      int i, j, ret = 0;
+      double *h, *r, *w;
+      /* save vector of right-hand sides h */
+      h = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) h[i] = y[i];
+      /* solve normal equation system (A*D*A')*y = h */
+      /* since S = P*A*D*A'*P' = U'*U, then A*D*A' = P'*U'*U*P, so we
+         have inv(A*D*A') = P'*inv(U)*inv(U')*P */
+      /* w := P*h */
+      w = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) w[i] = y[P[i]];
+      /* w := inv(U')*w */
+      ut_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
+      /* w := inv(U)*w */
+      u_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w);
+      /* y := P'*w */
+      for (i = 1; i <= m; i++) y[i] = w[P[m+i]];
+      xfree(w);
+      /* compute residual vector r = A*D*A'*y - h */
+      r = xcalloc(1+m, sizeof(double));
+      /* w := A'*y */
+      w = xcalloc(1+n, sizeof(double));
+      AT_by_vec(csa, y, w);
+      /* w := D*w */
+      for (j = 1; j <= n; j++) w[j] *= csa->D[j];
+      /* r := A*w */
+      A_by_vec(csa, w, r);
+      xfree(w);
+      /* r := r - h */
+      for (i = 1; i <= m; i++) r[i] -= h[i];
+      /* check for numeric stability */
+      for (i = 1; i <= m; i++)
+      {  if (fabs(r[i]) / (1.0 + fabs(h[i])) > 1e-4)
+         {  ret = 1;
+            break;
+         }
+      }
+      xfree(h);
+      xfree(r);
+      return ret;
+}
+
+/***********************************************************************
+*  solve_NS - solve Newtonian system
+*
+*  This routine solves the Newtonian system:
+*
+*     A*dx               = p
+*
+*           A'*dy +   dz = q
+*
+*     Z*dx        + X*dz = r
+*
+*  where X = diag(x[j]), Z = diag(z[j]), by reducing it to the normal
+*  equation system:
+*
+*     (A*inv(Z)*X*A')*dy = A*inv(Z)*(X*q-r)+p
+*
+*  (it is assumed that the matrix A*inv(Z)*X*A' has been factorized by
+*  the routine decomp_NE).
+*
+*  Once vector dy has been computed the routine computes vectors dx and
+*  dz as follows:
+*
+*     dx = inv(Z)*(X*(A'*dy-q)+r)
+*
+*     dz = inv(X)*(r-Z*dx)
+*
+*  The routine solve_NS returns the same code which was reported by the
+*  routine solve_NE (see above). */
+
+static int solve_NS(struct csa *csa, double p[], double q[], double r[],
+      double dx[], double dy[], double dz[])
+{     int m = csa->m;
+      int n = csa->n;
+      double *x = csa->x;
+      double *z = csa->z;
+      int i, j, ret;
+      double *w = dx;
+      /* compute the vector of right-hand sides A*inv(Z)*(X*q-r)+p for
+         the normal equation system */
+      for (j = 1; j <= n; j++)
+         w[j] = (x[j] * q[j] - r[j]) / z[j];
+      A_by_vec(csa, w, dy);
+      for (i = 1; i <= m; i++) dy[i] += p[i];
+      /* solve the normal equation system to compute vector dy */
+      ret = solve_NE(csa, dy);
+      /* compute vectors dx and dz */
+      AT_by_vec(csa, dy, dx);
+      for (j = 1; j <= n; j++)
+      {  dx[j] = (x[j] * (dx[j] - q[j]) + r[j]) / z[j];
+         dz[j] = (r[j] - z[j] * dx[j]) / x[j];
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  initial_point - choose initial point using Mehrotra's heuristic
+*
+*  This routine chooses a starting point using a heuristic proposed in
+*  the paper:
+*
+*  S. Mehrotra. On the implementation of a primal-dual interior point
+*  method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
+*
+*  The starting point x in the primal space is chosen as a solution of
+*  the following least squares problem:
+*
+*     minimize    ||x||
+*
+*     subject to  A*x = b
+*
+*  which can be computed explicitly as follows:
+*
+*     x = A'*inv(A*A')*b
+*
+*  Similarly, the starting point (y, z) in the dual space is chosen as
+*  a solution of the following least squares problem:
+*
+*     minimize    ||z||
+*
+*     subject to  A'*y + z = c
+*
+*  which can be computed explicitly as follows:
+*
+*     y = inv(A*A')*A*c
+*
+*     z = c - A'*y
+*
+*  However, some components of the vectors x and z may be non-positive
+*  or close to zero, so the routine uses a Mehrotra's heuristic to find
+*  a more appropriate starting point. */
+
+static void initial_point(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *b = csa->b;
+      double *c = csa->c;
+      double *x = csa->x;
+      double *y = csa->y;
+      double *z = csa->z;
+      double *D = csa->D;
+      int i, j;
+      double dp, dd, ex, ez, xz;
+      /* factorize A*A' */
+      for (j = 1; j <= n; j++) D[j] = 1.0;
+      decomp_NE(csa);
+      /* x~ = A'*inv(A*A')*b */
+      for (i = 1; i <= m; i++) y[i] = b[i];
+      solve_NE(csa, y);
+      AT_by_vec(csa, y, x);
+      /* y~ = inv(A*A')*A*c */
+      A_by_vec(csa, c, y);
+      solve_NE(csa, y);
+      /* z~ = c - A'*y~ */
+      AT_by_vec(csa, y,z);
+      for (j = 1; j <= n; j++) z[j] = c[j] - z[j];
+      /* use Mehrotra's heuristic in order to choose more appropriate
+         starting point with positive components of vectors x and z */
+      dp = dd = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (dp < -1.5 * x[j]) dp = -1.5 * x[j];
+         if (dd < -1.5 * z[j]) dd = -1.5 * z[j];
+      }
+      /* note that b = 0 involves x = 0, and c = 0 involves y = 0 and
+         z = 0, so we need to be careful */
+      if (dp == 0.0) dp = 1.5;
+      if (dd == 0.0) dd = 1.5;
+      ex = ez = xz = 0.0;
+      for (j = 1; j <= n; j++)
+      {  ex += (x[j] + dp);
+         ez += (z[j] + dd);
+         xz += (x[j] + dp) * (z[j] + dd);
+      }
+      dp += 0.5 * (xz / ez);
+      dd += 0.5 * (xz / ex);
+      for (j = 1; j <= n; j++)
+      {  x[j] += dp;
+         z[j] += dd;
+         xassert(x[j] > 0.0 && z[j] > 0.0);
+      }
+      return;
+}
+
+/***********************************************************************
+*  basic_info - perform basic computations at the current point
+*
+*  This routine computes the following quantities at the current point:
+*
+*  1) value of the objective function:
+*
+*     F = c'*x + c[0]
+*
+*  2) relative primal infeasibility:
+*
+*     rpi = ||A*x-b|| / (1+||b||)
+*
+*  3) relative dual infeasibility:
+*
+*     rdi = ||A'*y+z-c|| / (1+||c||)
+*
+*  4) primal-dual gap (relative difference between the primal and the
+*     dual objective function values):
+*
+*     gap = |c'*x-b'*y| / (1+|c'*x|)
+*
+*  5) merit function:
+*
+*     phi = ||A*x-b|| / max(1,||b||) + ||A'*y+z-c|| / max(1,||c||) +
+*
+*         + |c'*x-b'*y| / max(1,||b||,||c||)
+*
+*  6) duality measure:
+*
+*     mu = x'*z / n
+*
+*  7) the ratio of infeasibility to mu:
+*
+*     rmu = max(||A*x-b||,||A'*y+z-c||) / mu
+*
+*  where ||*|| denotes euclidian norm, *' denotes transposition. */
+
+static void basic_info(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *b = csa->b;
+      double *c = csa->c;
+      double *x = csa->x;
+      double *y = csa->y;
+      double *z = csa->z;
+      int i, j;
+      double norm1, bnorm, norm2, cnorm, cx, by, *work, temp;
+      /* compute value of the objective function */
+      temp = c[0];
+      for (j = 1; j <= n; j++) temp += c[j] * x[j];
+      csa->obj = temp;
+      /* norm1 = ||A*x-b|| */
+      work = xcalloc(1+m, sizeof(double));
+      A_by_vec(csa, x, work);
+      norm1 = 0.0;
+      for (i = 1; i <= m; i++)
+         norm1 += (work[i] - b[i]) * (work[i] - b[i]);
+      norm1 = sqrt(norm1);
+      xfree(work);
+      /* bnorm = ||b|| */
+      bnorm = 0.0;
+      for (i = 1; i <= m; i++) bnorm += b[i] * b[i];
+      bnorm = sqrt(bnorm);
+      /* compute relative primal infeasibility */
+      csa->rpi = norm1 / (1.0 + bnorm);
+      /* norm2 = ||A'*y+z-c|| */
+      work = xcalloc(1+n, sizeof(double));
+      AT_by_vec(csa, y, work);
+      norm2 = 0.0;
+      for (j = 1; j <= n; j++)
+         norm2 += (work[j] + z[j] - c[j]) * (work[j] + z[j] - c[j]);
+      norm2 = sqrt(norm2);
+      xfree(work);
+      /* cnorm = ||c|| */
+      cnorm = 0.0;
+      for (j = 1; j <= n; j++) cnorm += c[j] * c[j];
+      cnorm = sqrt(cnorm);
+      /* compute relative dual infeasibility */
+      csa->rdi = norm2 / (1.0 + cnorm);
+      /* by = b'*y */
+      by = 0.0;
+      for (i = 1; i <= m; i++) by += b[i] * y[i];
+      /* cx = c'*x */
+      cx = 0.0;
+      for (j = 1; j <= n; j++) cx += c[j] * x[j];
+      /* compute primal-dual gap */
+      csa->gap = fabs(cx - by) / (1.0 + fabs(cx));
+      /* compute merit function */
+      csa->phi = 0.0;
+      csa->phi += norm1 / (bnorm > 1.0 ? bnorm : 1.0);
+      csa->phi += norm2 / (cnorm > 1.0 ? cnorm : 1.0);
+      temp = 1.0;
+      if (temp < bnorm) temp = bnorm;
+      if (temp < cnorm) temp = cnorm;
+      csa->phi += fabs(cx - by) / temp;
+      /* compute duality measure */
+      temp = 0.0;
+      for (j = 1; j <= n; j++) temp += x[j] * z[j];
+      csa->mu = temp / (double)n;
+      /* compute the ratio of infeasibility to mu */
+      csa->rmu = (norm1 > norm2 ? norm1 : norm2) / csa->mu;
+      return;
+}
+
+/***********************************************************************
+*  make_step - compute next point using Mehrotra's technique
+*
+*  This routine computes the next point using the predictor-corrector
+*  technique proposed in the paper:
+*
+*  S. Mehrotra. On the implementation of a primal-dual interior point
+*  method. SIAM J. on Optim., 2(4), pp. 575-601, 1992.
+*
+*  At first, the routine computes so called affine scaling (predictor)
+*  direction (dx_aff,dy_aff,dz_aff) which is a solution of the system:
+*
+*     A*dx_aff                       = b - A*x
+*
+*               A'*dy_aff +   dz_aff = c - A'*y - z
+*
+*     Z*dx_aff            + X*dz_aff = - X*Z*e
+*
+*  where (x,y,z) is the current point, X = diag(x[j]), Z = diag(z[j]),
+*  e = (1,...,1)'.
+*
+*  Then, the routine computes the centering parameter sigma, using the
+*  following Mehrotra's heuristic:
+*
+*     alfa_aff_p = inf{0 <= alfa <= 1 | x+alfa*dx_aff >= 0}
+*
+*     alfa_aff_d = inf{0 <= alfa <= 1 | z+alfa*dz_aff >= 0}
+*
+*     mu_aff = (x+alfa_aff_p*dx_aff)'*(z+alfa_aff_d*dz_aff)/n
+*
+*     sigma = (mu_aff/mu)^3
+*
+*  where alfa_aff_p is the maximal stepsize along the affine scaling
+*  direction in the primal space, alfa_aff_d is the maximal stepsize
+*  along the same direction in the dual space.
+*
+*  After determining sigma the routine computes so called centering
+*  (corrector) direction (dx_cc,dy_cc,dz_cc) which is the solution of
+*  the system:
+*
+*     A*dx_cc                     = 0
+*
+*              A'*dy_cc +   dz_cc = 0
+*
+*     Z*dx_cc           + X*dz_cc = sigma*mu*e - X*Z*e
+*
+*  Finally, the routine computes the combined direction
+*
+*     (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc)
+*
+*  and determines maximal primal and dual stepsizes along the combined
+*  direction:
+*
+*     alfa_max_p = inf{0 <= alfa <= 1 | x+alfa*dx >= 0}
+*
+*     alfa_max_d = inf{0 <= alfa <= 1 | z+alfa*dz >= 0}
+*
+*  In order to prevent the next point to be too close to the boundary
+*  of the positive ortant, the routine decreases maximal stepsizes:
+*
+*     alfa_p = gamma_p * alfa_max_p
+*
+*     alfa_d = gamma_d * alfa_max_d
+*
+*  where gamma_p and gamma_d are scaling factors, and computes the next
+*  point:
+*
+*     x_new = x + alfa_p * dx
+*
+*     y_new = y + alfa_d * dy
+*
+*     z_new = z + alfa_d * dz
+*
+*  which becomes the current point on the next iteration. */
+
+static int make_step(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *b = csa->b;
+      double *c = csa->c;
+      double *x = csa->x;
+      double *y = csa->y;
+      double *z = csa->z;
+      double *dx_aff = csa->dx_aff;
+      double *dy_aff = csa->dy_aff;
+      double *dz_aff = csa->dz_aff;
+      double *dx_cc = csa->dx_cc;
+      double *dy_cc = csa->dy_cc;
+      double *dz_cc = csa->dz_cc;
+      double *dx = csa->dx;
+      double *dy = csa->dy;
+      double *dz = csa->dz;
+      int i, j, ret = 0;
+      double temp, gamma_p, gamma_d, *p, *q, *r;
+      /* allocate working arrays */
+      p = xcalloc(1+m, sizeof(double));
+      q = xcalloc(1+n, sizeof(double));
+      r = xcalloc(1+n, sizeof(double));
+      /* p = b - A*x */
+      A_by_vec(csa, x, p);
+      for (i = 1; i <= m; i++) p[i] = b[i] - p[i];
+      /* q = c - A'*y - z */
+      AT_by_vec(csa, y,q);
+      for (j = 1; j <= n; j++) q[j] = c[j] - q[j] - z[j];
+      /* r = - X * Z * e */
+      for (j = 1; j <= n; j++) r[j] = - x[j] * z[j];
+      /* solve the first Newtonian system */
+      if (solve_NS(csa, p, q, r, dx_aff, dy_aff, dz_aff))
+      {  ret = 1;
+         goto done;
+      }
+      /* alfa_aff_p = inf{0 <= alfa <= 1 | x + alfa*dx_aff >= 0} */
+      /* alfa_aff_d = inf{0 <= alfa <= 1 | z + alfa*dz_aff >= 0} */
+      csa->alfa_aff_p = csa->alfa_aff_d = 1.0;
+      for (j = 1; j <= n; j++)
+      {  if (dx_aff[j] < 0.0)
+         {  temp = - x[j] / dx_aff[j];
+            if (csa->alfa_aff_p > temp) csa->alfa_aff_p = temp;
+         }
+         if (dz_aff[j] < 0.0)
+         {  temp = - z[j] / dz_aff[j];
+            if (csa->alfa_aff_d > temp) csa->alfa_aff_d = temp;
+         }
+      }
+      /* mu_aff = (x+alfa_aff_p*dx_aff)' * (z+alfa_aff_d*dz_aff) / n */
+      temp = 0.0;
+      for (j = 1; j <= n; j++)
+         temp += (x[j] + csa->alfa_aff_p * dx_aff[j]) *
+                 (z[j] + csa->alfa_aff_d * dz_aff[j]);
+      csa->mu_aff = temp / (double)n;
+      /* sigma = (mu_aff/mu)^3 */
+      temp = csa->mu_aff / csa->mu;
+      csa->sigma = temp * temp * temp;
+      /* p = 0 */
+      for (i = 1; i <= m; i++) p[i] = 0.0;
+      /* q = 0 */
+      for (j = 1; j <= n; j++) q[j] = 0.0;
+      /* r = sigma * mu * e - X * Z * e */
+      for (j = 1; j <= n; j++)
+         r[j] = csa->sigma * csa->mu - dx_aff[j] * dz_aff[j];
+      /* solve the second Newtonian system with the same coefficients
+         but with altered right-hand sides */
+      if (solve_NS(csa, p, q, r, dx_cc, dy_cc, dz_cc))
+      {  ret = 1;
+         goto done;
+      }
+      /* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) */
+      for (j = 1; j <= n; j++) dx[j] = dx_aff[j] + dx_cc[j];
+      for (i = 1; i <= m; i++) dy[i] = dy_aff[i] + dy_cc[i];
+      for (j = 1; j <= n; j++) dz[j] = dz_aff[j] + dz_cc[j];
+      /* alfa_max_p = inf{0 <= alfa <= 1 | x + alfa*dx >= 0} */
+      /* alfa_max_d = inf{0 <= alfa <= 1 | z + alfa*dz >= 0} */
+      csa->alfa_max_p = csa->alfa_max_d = 1.0;
+      for (j = 1; j <= n; j++)
+      {  if (dx[j] < 0.0)
+         {  temp = - x[j] / dx[j];
+            if (csa->alfa_max_p > temp) csa->alfa_max_p = temp;
+         }
+         if (dz[j] < 0.0)
+         {  temp = - z[j] / dz[j];
+            if (csa->alfa_max_d > temp) csa->alfa_max_d = temp;
+         }
+      }
+      /* determine scale factors (not implemented yet) */
+      gamma_p = 0.90;
+      gamma_d = 0.90;
+      /* compute the next point */
+      for (j = 1; j <= n; j++)
+      {  x[j] += gamma_p * csa->alfa_max_p * dx[j];
+         xassert(x[j] > 0.0);
+      }
+      for (i = 1; i <= m; i++)
+         y[i] += gamma_d * csa->alfa_max_d * dy[i];
+      for (j = 1; j <= n; j++)
+      {  z[j] += gamma_d * csa->alfa_max_d * dz[j];
+         xassert(z[j] > 0.0);
+      }
+done: /* free working arrays */
+      xfree(p);
+      xfree(q);
+      xfree(r);
+      return ret;
+}
+
+/***********************************************************************
+*  terminate - deallocate common storage area
+*
+*  This routine frees all memory allocated to the common storage area
+*  used by interior-point method routines. */
+
+static void terminate(struct csa *csa)
+{     xfree(csa->D);
+      xfree(csa->P);
+      xfree(csa->S_ptr);
+      xfree(csa->S_ind);
+      xfree(csa->S_val);
+      xfree(csa->S_diag);
+      xfree(csa->U_ptr);
+      xfree(csa->U_ind);
+      xfree(csa->U_val);
+      xfree(csa->U_diag);
+      xfree(csa->phi_min);
+      xfree(csa->best_x);
+      xfree(csa->best_y);
+      xfree(csa->best_z);
+      xfree(csa->dx_aff);
+      xfree(csa->dy_aff);
+      xfree(csa->dz_aff);
+      xfree(csa->dx_cc);
+      xfree(csa->dy_cc);
+      xfree(csa->dz_cc);
+      return;
+}
+
+/***********************************************************************
+*  ipm_main - main interior-point method routine
+*
+*  This is a main routine of the primal-dual interior-point method.
+*
+*  The routine ipm_main returns one of the following codes:
+*
+*  0 - optimal solution found;
+*  1 - problem has no feasible (primal or dual) solution;
+*  2 - no convergence;
+*  3 - iteration limit exceeded;
+*  4 - numeric instability on solving Newtonian system.
+*
+*  In case of non-zero return code the routine returns the best point,
+*  which has been reached during optimization. */
+
+static int ipm_main(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int i, j, status;
+      double temp;
+      /* choose initial point using Mehrotra's heuristic */
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Guessing initial point...\n");
+      initial_point(csa);
+      /* main loop starts here */
+      if (csa->parm->msg_lev >= GLP_MSG_ALL)
+         xprintf("Optimization begins...\n");
+      for (;;)
+      {  /* perform basic computations at the current point */
+         basic_info(csa);
+         /* save initial value of rmu */
+         if (csa->iter == 0) csa->rmu0 = csa->rmu;
+         /* accumulate values of min(phi[k]) and save the best point */
+         xassert(csa->iter <= ITER_MAX);
+         if (csa->iter == 0 || csa->phi_min[csa->iter-1] > csa->phi)
+         {  csa->phi_min[csa->iter] = csa->phi;
+            csa->best_iter = csa->iter;
+            for (j = 1; j <= n; j++) csa->best_x[j] = csa->x[j];
+            for (i = 1; i <= m; i++) csa->best_y[i] = csa->y[i];
+            for (j = 1; j <= n; j++) csa->best_z[j] = csa->z[j];
+            csa->best_obj = csa->obj;
+         }
+         else
+            csa->phi_min[csa->iter] = csa->phi_min[csa->iter-1];
+         /* display information at the current point */
+         if (csa->parm->msg_lev >= GLP_MSG_ON)
+            xprintf("%3d: obj = %17.9e; rpi = %8.1e; rdi = %8.1e; gap ="
+               " %8.1e\n", csa->iter, csa->obj, csa->rpi, csa->rdi,
+               csa->gap);
+         /* check if the current point is optimal */
+         if (csa->rpi < 1e-8 && csa->rdi < 1e-8 && csa->gap < 1e-8)
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("OPTIMAL SOLUTION FOUND\n");
+            status = 0;
+            break;
+         }
+         /* check if the problem has no feasible solution */
+         temp = 1e5 * csa->phi_min[csa->iter];
+         if (temp < 1e-8) temp = 1e-8;
+         if (csa->phi >= temp)
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("PROBLEM HAS NO FEASIBLE PRIMAL/DUAL SOLUTION\n")
+                  ;
+            status = 1;
+            break;
+         }
+         /* check for very slow convergence or divergence */
+         if (((csa->rpi >= 1e-8 || csa->rdi >= 1e-8) && csa->rmu /
+               csa->rmu0 >= 1e6) ||
+               (csa->iter >= 30 && csa->phi_min[csa->iter] >= 0.5 *
+               csa->phi_min[csa->iter - 30]))
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("NO CONVERGENCE; SEARCH TERMINATED\n");
+            status = 2;
+            break;
+         }
+         /* check for maximal number of iterations */
+         if (csa->iter == ITER_MAX)
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            status = 3;
+            break;
+         }
+         /* start the next iteration */
+         csa->iter++;
+         /* factorize normal equation system */
+         for (j = 1; j <= n; j++) csa->D[j] = csa->x[j] / csa->z[j];
+         decomp_NE(csa);
+         /* compute the next point using Mehrotra's predictor-corrector
+            technique */
+         if (make_step(csa))
+         {  if (csa->parm->msg_lev >= GLP_MSG_ALL)
+               xprintf("NUMERIC INSTABILITY; SEARCH TERMINATED\n");
+            status = 4;
+            break;
+         }
+      }
+      /* restore the best point */
+      if (status != 0)
+      {  for (j = 1; j <= n; j++) csa->x[j] = csa->best_x[j];
+         for (i = 1; i <= m; i++) csa->y[i] = csa->best_y[i];
+         for (j = 1; j <= n; j++) csa->z[j] = csa->best_z[j];
+         if (csa->parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("Best point %17.9e was reached on iteration %d\n",
+               csa->best_obj, csa->best_iter);
+      }
+      /* return to the calling program */
+      return status;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  ipm_solve - core LP solver based on the interior-point method
+*
+*  SYNOPSIS
+*
+*  #include "glpipm.h"
+*  int ipm_solve(glp_prob *P, const glp_iptcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine ipm_solve is a core LP solver based on the primal-dual
+*  interior-point method.
+*
+*  The routine assumes the following standard formulation of LP problem
+*  to be solved:
+*
+*     minimize
+*
+*        F = c[0] + c[1]*x[1] + c[2]*x[2] + ... + c[n]*x[n]
+*
+*     subject to linear constraints
+*
+*        a[1,1]*x[1] + a[1,2]*x[2] + ... + a[1,n]*x[n] = b[1]
+*
+*        a[2,1]*x[1] + a[2,2]*x[2] + ... + a[2,n]*x[n] = b[2]
+*
+*              . . . . . .
+*
+*        a[m,1]*x[1] + a[m,2]*x[2] + ... + a[m,n]*x[n] = b[m]
+*
+*     and non-negative variables
+*
+*        x[1] >= 0, x[2] >= 0, ..., x[n] >= 0
+*
+*  where:
+*  F                    is the objective function;
+*  x[1], ..., x[n]      are (structural) variables;
+*  c[0]                 is a constant term of the objective function;
+*  c[1], ..., c[n]      are objective coefficients;
+*  a[1,1], ..., a[m,n]  are constraint coefficients;
+*  b[1], ..., b[n]      are right-hand sides.
+*
+*  The solution is three vectors x, y, and z, which are stored by the
+*  routine in the arrays x, y, and z, respectively. These vectors
+*  correspond to the best primal-dual point found during optimization.
+*  They are approximate solution of the following system (which is the
+*  Karush-Kuhn-Tucker optimality conditions):
+*
+*     A*x      = b      (primal feasibility condition)
+*
+*     A'*y + z = c      (dual feasibility condition)
+*
+*     x'*z     = 0      (primal-dual complementarity condition)
+*
+*     x >= 0, z >= 0    (non-negativity condition)
+*
+*  where:
+*  x[1], ..., x[n]      are primal (structural) variables;
+*  y[1], ..., y[m]      are dual variables (Lagrange multipliers) for
+*                       equality constraints;
+*  z[1], ..., z[n]      are dual variables (Lagrange multipliers) for
+*                       non-negativity constraints.
+*
+*  RETURNS
+*
+*  0  LP has been successfully solved.
+*
+*  GLP_ENOCVG
+*     No convergence.
+*
+*  GLP_EITLIM
+*     Iteration limit exceeded.
+*
+*  GLP_EINSTAB
+*     Numeric instability on solving Newtonian system.
+*
+*  In case of non-zero return code the routine returns the best point,
+*  which has been reached during optimization. */
+
+int ipm_solve(glp_prob *P, const glp_iptcp *parm)
+{     struct csa _dsa, *csa = &_dsa;
+      int m = P->m;
+      int n = P->n;
+      int nnz = P->nnz;
+      GLPROW *row;
+      GLPCOL *col;
+      GLPAIJ *aij;
+      int i, j, loc, ret, *A_ind, *A_ptr;
+      double dir, *A_val, *b, *c, *x, *y, *z;
+      xassert(m > 0);
+      xassert(n > 0);
+      /* allocate working arrays */
+      A_ptr = xcalloc(1+m+1, sizeof(int));
+      A_ind = xcalloc(1+nnz, sizeof(int));
+      A_val = xcalloc(1+nnz, sizeof(double));
+      b = xcalloc(1+m, sizeof(double));
+      c = xcalloc(1+n, sizeof(double));
+      x = xcalloc(1+n, sizeof(double));
+      y = xcalloc(1+m, sizeof(double));
+      z = xcalloc(1+n, sizeof(double));
+      /* prepare rows and constraint coefficients */
+      loc = 1;
+      for (i = 1; i <= m; i++)
+      {  row = P->row[i];
+         xassert(row->type == GLP_FX);
+         b[i] = row->lb * row->rii;
+         A_ptr[i] = loc;
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  A_ind[loc] = aij->col->j;
+            A_val[loc] = row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      A_ptr[m+1] = loc;
+      xassert(loc-1 == nnz);
+      /* prepare columns and objective coefficients */
+      if (P->dir == GLP_MIN)
+         dir = +1.0;
+      else if (P->dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(P != P);
+      c[0] = dir * P->c0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         xassert(col->type == GLP_LO && col->lb == 0.0);
+         c[j] = dir * col->coef * col->sjj;
+      }
+      /* allocate and initialize the common storage area */
+      csa->m = m;
+      csa->n = n;
+      csa->A_ptr = A_ptr;
+      csa->A_ind = A_ind;
+      csa->A_val = A_val;
+      csa->b = b;
+      csa->c = c;
+      csa->x = x;
+      csa->y = y;
+      csa->z = z;
+      csa->parm = parm;
+      initialize(csa);
+      /* solve LP with the interior-point method */
+      ret = ipm_main(csa);
+      /* deallocate the common storage area */
+      terminate(csa);
+      /* determine solution status */
+      if (ret == 0)
+      {  /* optimal solution found */
+         P->ipt_stat = GLP_OPT;
+         ret = 0;
+      }
+      else if (ret == 1)
+      {  /* problem has no feasible (primal or dual) solution */
+         P->ipt_stat = GLP_NOFEAS;
+         ret = 0;
+      }
+      else if (ret == 2)
+      {  /* no convergence */
+         P->ipt_stat = GLP_INFEAS;
+         ret = GLP_ENOCVG;
+      }
+      else if (ret == 3)
+      {  /* iteration limit exceeded */
+         P->ipt_stat = GLP_INFEAS;
+         ret = GLP_EITLIM;
+      }
+      else if (ret == 4)
+      {  /* numeric instability on solving Newtonian system */
+         P->ipt_stat = GLP_INFEAS;
+         ret = GLP_EINSTAB;
+      }
+      else
+         xassert(ret != ret);
+      /* store row solution components */
+      for (i = 1; i <= m; i++)
+      {  row = P->row[i];
+         row->pval = row->lb;
+         row->dval = dir * y[i] * row->rii;
+      }
+      /* store column solution components */
+      P->ipt_obj = P->c0;
+      for (j = 1; j <= n; j++)
+      {  col = P->col[j];
+         col->pval = x[j] * col->sjj;
+         col->dval = dir * z[j] / col->sjj;
+         P->ipt_obj += col->coef * col->pval;
+      }
+      /* free working arrays */
+      xfree(A_ptr);
+      xfree(A_ind);
+      xfree(A_val);
+      xfree(b);
+      xfree(c);
+      xfree(x);
+      xfree(y);
+      xfree(z);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpipm.h
===================================================================
--- deps/glpk/src/glpipm.h	(revision 9)
+++ deps/glpk/src/glpipm.h	(revision 9)
@@ -0,0 +1,36 @@
+/* glpipm.h (primal-dual interior-point method) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPIPM_H
+#define GLPIPM_H
+
+#include "glpapi.h"
+
+#define ipm_solve _glp_ipm_solve
+int ipm_solve(glp_prob *P, const glp_iptcp *parm);
+/* core LP solver based on the interior-point method */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpk.h
===================================================================
--- deps/glpk/src/glpk.h	(revision 9)
+++ deps/glpk/src/glpk.h	(revision 9)
@@ -0,0 +1,1767 @@
+/* glpk.h */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPK_H
+#define GLPK_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* library version numbers: */
+#define GLP_MAJOR_VERSION  4
+#define GLP_MINOR_VERSION  47
+
+#ifndef GLP_PROB_DEFINED
+#define GLP_PROB_DEFINED
+typedef struct { double _opaque_prob[100]; } glp_prob;
+/* LP/MIP problem object */
+#endif
+
+/* optimization direction flag: */
+#define GLP_MIN            1  /* minimization */
+#define GLP_MAX            2  /* maximization */
+
+/* kind of structural variable: */
+#define GLP_CV             1  /* continuous variable */
+#define GLP_IV             2  /* integer variable */
+#define GLP_BV             3  /* binary variable */
+
+/* type of auxiliary/structural variable: */
+#define GLP_FR             1  /* free variable */
+#define GLP_LO             2  /* variable with lower bound */
+#define GLP_UP             3  /* variable with upper bound */
+#define GLP_DB             4  /* double-bounded variable */
+#define GLP_FX             5  /* fixed variable */
+
+/* status of auxiliary/structural variable: */
+#define GLP_BS             1  /* basic variable */
+#define GLP_NL             2  /* non-basic variable on lower bound */
+#define GLP_NU             3  /* non-basic variable on upper bound */
+#define GLP_NF             4  /* non-basic free variable */
+#define GLP_NS             5  /* non-basic fixed variable */
+
+/* scaling options: */
+#define GLP_SF_GM       0x01  /* perform geometric mean scaling */
+#define GLP_SF_EQ       0x10  /* perform equilibration scaling */
+#define GLP_SF_2N       0x20  /* round scale factors to power of two */
+#define GLP_SF_SKIP     0x40  /* skip if problem is well scaled */
+#define GLP_SF_AUTO     0x80  /* choose scaling options automatically */
+
+/* solution indicator: */
+#define GLP_SOL            1  /* basic solution */
+#define GLP_IPT            2  /* interior-point solution */
+#define GLP_MIP            3  /* mixed integer solution */
+
+/* solution status: */
+#define GLP_UNDEF          1  /* solution is undefined */
+#define GLP_FEAS           2  /* solution is feasible */
+#define GLP_INFEAS         3  /* solution is infeasible */
+#define GLP_NOFEAS         4  /* no feasible solution exists */
+#define GLP_OPT            5  /* solution is optimal */
+#define GLP_UNBND          6  /* solution is unbounded */
+
+typedef struct
+{     /* basis factorization control parameters */
+      int msg_lev;            /* (reserved) */
+      int type;               /* factorization type: */
+#define GLP_BF_FT          1  /* LUF + Forrest-Tomlin */
+#define GLP_BF_BG          2  /* LUF + Schur compl. + Bartels-Golub */
+#define GLP_BF_GR          3  /* LUF + Schur compl. + Givens rotation */
+      int lu_size;            /* luf.sv_size */
+      double piv_tol;         /* luf.piv_tol */
+      int piv_lim;            /* luf.piv_lim */
+      int suhl;               /* luf.suhl */
+      double eps_tol;         /* luf.eps_tol */
+      double max_gro;         /* luf.max_gro */
+      int nfs_max;            /* fhv.hh_max */
+      double upd_tol;         /* fhv.upd_tol */
+      int nrs_max;            /* lpf.n_max */
+      int rs_size;            /* lpf.v_size */
+      double foo_bar[38];     /* (reserved) */
+} glp_bfcp;
+
+typedef struct
+{     /* simplex method control parameters */
+      int msg_lev;            /* message level: */
+#define GLP_MSG_OFF        0  /* no output */
+#define GLP_MSG_ERR        1  /* warning and error messages only */
+#define GLP_MSG_ON         2  /* normal output */
+#define GLP_MSG_ALL        3  /* full output */
+#define GLP_MSG_DBG        4  /* debug output */
+      int meth;               /* simplex method option: */
+#define GLP_PRIMAL         1  /* use primal simplex */
+#define GLP_DUALP          2  /* use dual; if it fails, use primal */
+#define GLP_DUAL           3  /* use dual simplex */
+      int pricing;            /* pricing technique: */
+#define GLP_PT_STD      0x11  /* standard (Dantzig rule) */
+#define GLP_PT_PSE      0x22  /* projected steepest edge */
+      int r_test;             /* ratio test technique: */
+#define GLP_RT_STD      0x11  /* standard (textbook) */
+#define GLP_RT_HAR      0x22  /* two-pass Harris' ratio test */
+      double tol_bnd;         /* spx.tol_bnd */
+      double tol_dj;          /* spx.tol_dj */
+      double tol_piv;         /* spx.tol_piv */
+      double obj_ll;          /* spx.obj_ll */
+      double obj_ul;          /* spx.obj_ul */
+      int it_lim;             /* spx.it_lim */
+      int tm_lim;             /* spx.tm_lim (milliseconds) */
+      int out_frq;            /* spx.out_frq */
+      int out_dly;            /* spx.out_dly (milliseconds) */
+      int presolve;           /* enable/disable using LP presolver */
+      double foo_bar[36];     /* (reserved) */
+} glp_smcp;
+
+typedef struct
+{     /* interior-point solver control parameters */
+      int msg_lev;            /* message level (see glp_smcp) */
+      int ord_alg;            /* ordering algorithm: */
+#define GLP_ORD_NONE       0  /* natural (original) ordering */
+#define GLP_ORD_QMD        1  /* quotient minimum degree (QMD) */
+#define GLP_ORD_AMD        2  /* approx. minimum degree (AMD) */
+#define GLP_ORD_SYMAMD     3  /* approx. minimum degree (SYMAMD) */
+      double foo_bar[48];     /* (reserved) */
+} glp_iptcp;
+
+#ifndef GLP_TREE_DEFINED
+#define GLP_TREE_DEFINED
+typedef struct { double _opaque_tree[100]; } glp_tree;
+/* branch-and-bound tree */
+#endif
+
+typedef struct
+{     /* integer optimizer control parameters */
+      int msg_lev;            /* message level (see glp_smcp) */
+      int br_tech;            /* branching technique: */
+#define GLP_BR_FFV         1  /* first fractional variable */
+#define GLP_BR_LFV         2  /* last fractional variable */
+#define GLP_BR_MFV         3  /* most fractional variable */
+#define GLP_BR_DTH         4  /* heuristic by Driebeck and Tomlin */
+#define GLP_BR_PCH         5  /* hybrid pseudocost heuristic */
+      int bt_tech;            /* backtracking technique: */
+#define GLP_BT_DFS         1  /* depth first search */
+#define GLP_BT_BFS         2  /* breadth first search */
+#define GLP_BT_BLB         3  /* best local bound */
+#define GLP_BT_BPH         4  /* best projection heuristic */
+      double tol_int;         /* mip.tol_int */
+      double tol_obj;         /* mip.tol_obj */
+      int tm_lim;             /* mip.tm_lim (milliseconds) */
+      int out_frq;            /* mip.out_frq (milliseconds) */
+      int out_dly;            /* mip.out_dly (milliseconds) */
+      void (*cb_func)(glp_tree *T, void *info);
+                              /* mip.cb_func */
+      void *cb_info;          /* mip.cb_info */
+      int cb_size;            /* mip.cb_size */
+      int pp_tech;            /* preprocessing technique: */
+#define GLP_PP_NONE        0  /* disable preprocessing */
+#define GLP_PP_ROOT        1  /* preprocessing only on root level */
+#define GLP_PP_ALL         2  /* preprocessing on all levels */
+      double mip_gap;         /* relative MIP gap tolerance */
+      int mir_cuts;           /* MIR cuts       (GLP_ON/GLP_OFF) */
+      int gmi_cuts;           /* Gomory's cuts  (GLP_ON/GLP_OFF) */
+      int cov_cuts;           /* cover cuts     (GLP_ON/GLP_OFF) */
+      int clq_cuts;           /* clique cuts    (GLP_ON/GLP_OFF) */
+      int presolve;           /* enable/disable using MIP presolver */
+      int binarize;           /* try to binarize integer variables */
+      int fp_heur;            /* feasibility pump heuristic */
+#if 1 /* 28/V-2010 */
+      int alien;              /* use alien solver */
+#endif
+      double foo_bar[29];     /* (reserved) */
+} glp_iocp;
+
+typedef struct
+{     /* additional row attributes */
+      int level;
+      /* subproblem level at which the row was added */
+      int origin;
+      /* row origin flag: */
+#define GLP_RF_REG         0  /* regular constraint */
+#define GLP_RF_LAZY        1  /* "lazy" constraint */
+#define GLP_RF_CUT         2  /* cutting plane constraint */
+      int klass;
+      /* row class descriptor: */
+#define GLP_RF_GMI         1  /* Gomory's mixed integer cut */
+#define GLP_RF_MIR         2  /* mixed integer rounding cut */
+#define GLP_RF_COV         3  /* mixed cover cut */
+#define GLP_RF_CLQ         4  /* clique cut */
+      double foo_bar[7];
+      /* (reserved) */
+} glp_attr;
+
+/* enable/disable flag: */
+#define GLP_ON             1  /* enable something */
+#define GLP_OFF            0  /* disable something */
+
+/* reason codes: */
+#define GLP_IROWGEN     0x01  /* request for row generation */
+#define GLP_IBINGO      0x02  /* better integer solution found */
+#define GLP_IHEUR       0x03  /* request for heuristic solution */
+#define GLP_ICUTGEN     0x04  /* request for cut generation */
+#define GLP_IBRANCH     0x05  /* request for branching */
+#define GLP_ISELECT     0x06  /* request for subproblem selection */
+#define GLP_IPREPRO     0x07  /* request for preprocessing */
+
+/* branch selection indicator: */
+#define GLP_NO_BRNCH       0  /* select no branch */
+#define GLP_DN_BRNCH       1  /* select down-branch */
+#define GLP_UP_BRNCH       2  /* select up-branch */
+
+/* return codes: */
+#define GLP_EBADB       0x01  /* invalid basis */
+#define GLP_ESING       0x02  /* singular matrix */
+#define GLP_ECOND       0x03  /* ill-conditioned matrix */
+#define GLP_EBOUND      0x04  /* invalid bounds */
+#define GLP_EFAIL       0x05  /* solver failed */
+#define GLP_EOBJLL      0x06  /* objective lower limit reached */
+#define GLP_EOBJUL      0x07  /* objective upper limit reached */
+#define GLP_EITLIM      0x08  /* iteration limit exceeded */
+#define GLP_ETMLIM      0x09  /* time limit exceeded */
+#define GLP_ENOPFS      0x0A  /* no primal feasible solution */
+#define GLP_ENODFS      0x0B  /* no dual feasible solution */
+#define GLP_EROOT       0x0C  /* root LP optimum not provided */
+#define GLP_ESTOP       0x0D  /* search terminated by application */
+#define GLP_EMIPGAP     0x0E  /* relative mip gap tolerance reached */
+#define GLP_ENOFEAS     0x0F  /* no primal/dual feasible solution */
+#define GLP_ENOCVG      0x10  /* no convergence */
+#define GLP_EINSTAB     0x11  /* numerical instability */
+#define GLP_EDATA       0x12  /* invalid data */
+#define GLP_ERANGE      0x13  /* result out of range */
+
+/* condition indicator: */
+#define GLP_KKT_PE         1  /* primal equalities */
+#define GLP_KKT_PB         2  /* primal bounds */
+#define GLP_KKT_DE         3  /* dual equalities */
+#define GLP_KKT_DB         4  /* dual bounds */
+#define GLP_KKT_CS         5  /* complementary slackness */
+
+/* MPS file format: */
+#define GLP_MPS_DECK       1  /* fixed (ancient) */
+#define GLP_MPS_FILE       2  /* free (modern) */
+
+typedef struct
+{     /* MPS format control parameters */
+      int blank;
+      /* character code to replace blanks in symbolic names */
+      char *obj_name;
+      /* objective row name */
+      double tol_mps;
+      /* zero tolerance for MPS data */
+      double foo_bar[17];
+      /* (reserved for use in the future) */
+} glp_mpscp;
+
+typedef struct
+{     /* CPLEX LP format control parameters */
+      double foo_bar[20];
+      /* (reserved for use in the future) */
+} glp_cpxcp;
+
+#ifndef GLP_TRAN_DEFINED
+#define GLP_TRAN_DEFINED
+typedef struct { double _opaque_tran[100]; } glp_tran;
+/* MathProg translator workspace */
+#endif
+
+glp_prob *glp_create_prob(void);
+/* create problem object */
+
+void glp_set_prob_name(glp_prob *P, const char *name);
+/* assign (change) problem name */
+
+void glp_set_obj_name(glp_prob *P, const char *name);
+/* assign (change) objective function name */
+
+void glp_set_obj_dir(glp_prob *P, int dir);
+/* set (change) optimization direction flag */
+
+int glp_add_rows(glp_prob *P, int nrs);
+/* add new rows to problem object */
+
+int glp_add_cols(glp_prob *P, int ncs);
+/* add new columns to problem object */
+
+void glp_set_row_name(glp_prob *P, int i, const char *name);
+/* assign (change) row name */
+
+void glp_set_col_name(glp_prob *P, int j, const char *name);
+/* assign (change) column name */
+
+void glp_set_row_bnds(glp_prob *P, int i, int type, double lb,
+      double ub);
+/* set (change) row bounds */
+
+void glp_set_col_bnds(glp_prob *P, int j, int type, double lb,
+      double ub);
+/* set (change) column bounds */
+
+void glp_set_obj_coef(glp_prob *P, int j, double coef);
+/* set (change) obj. coefficient or constant term */
+
+void glp_set_mat_row(glp_prob *P, int i, int len, const int ind[],
+      const double val[]);
+/* set (replace) row of the constraint matrix */
+
+void glp_set_mat_col(glp_prob *P, int j, int len, const int ind[],
+      const double val[]);
+/* set (replace) column of the constraint matrix */
+
+void glp_load_matrix(glp_prob *P, int ne, const int ia[],
+      const int ja[], const double ar[]);
+/* load (replace) the whole constraint matrix */
+
+int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]);
+/* check for duplicate elements in sparse matrix */
+
+void glp_sort_matrix(glp_prob *P);
+/* sort elements of the constraint matrix */
+
+void glp_del_rows(glp_prob *P, int nrs, const int num[]);
+/* delete specified rows from problem object */
+
+void glp_del_cols(glp_prob *P, int ncs, const int num[]);
+/* delete specified columns from problem object */
+
+void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
+/* copy problem object content */
+
+void glp_erase_prob(glp_prob *P);
+/* erase problem object content */
+
+void glp_delete_prob(glp_prob *P);
+/* delete problem object */
+
+const char *glp_get_prob_name(glp_prob *P);
+/* retrieve problem name */
+
+const char *glp_get_obj_name(glp_prob *P);
+/* retrieve objective function name */
+
+int glp_get_obj_dir(glp_prob *P);
+/* retrieve optimization direction flag */
+
+int glp_get_num_rows(glp_prob *P);
+/* retrieve number of rows */
+
+int glp_get_num_cols(glp_prob *P);
+/* retrieve number of columns */
+
+const char *glp_get_row_name(glp_prob *P, int i);
+/* retrieve row name */
+
+const char *glp_get_col_name(glp_prob *P, int j);
+/* retrieve column name */
+
+int glp_get_row_type(glp_prob *P, int i);
+/* retrieve row type */
+
+double glp_get_row_lb(glp_prob *P, int i);
+/* retrieve row lower bound */
+
+double glp_get_row_ub(glp_prob *P, int i);
+/* retrieve row upper bound */
+
+int glp_get_col_type(glp_prob *P, int j);
+/* retrieve column type */
+
+double glp_get_col_lb(glp_prob *P, int j);
+/* retrieve column lower bound */
+
+double glp_get_col_ub(glp_prob *P, int j);
+/* retrieve column upper bound */
+
+double glp_get_obj_coef(glp_prob *P, int j);
+/* retrieve obj. coefficient or constant term */
+
+int glp_get_num_nz(glp_prob *P);
+/* retrieve number of constraint coefficients */
+
+int glp_get_mat_row(glp_prob *P, int i, int ind[], double val[]);
+/* retrieve row of the constraint matrix */
+
+int glp_get_mat_col(glp_prob *P, int j, int ind[], double val[]);
+/* retrieve column of the constraint matrix */
+
+void glp_create_index(glp_prob *P);
+/* create the name index */
+
+int glp_find_row(glp_prob *P, const char *name);
+/* find row by its name */
+
+int glp_find_col(glp_prob *P, const char *name);
+/* find column by its name */
+
+void glp_delete_index(glp_prob *P);
+/* delete the name index */
+
+void glp_set_rii(glp_prob *P, int i, double rii);
+/* set (change) row scale factor */
+
+void glp_set_sjj(glp_prob *P, int j, double sjj);
+/* set (change) column scale factor */
+
+double glp_get_rii(glp_prob *P, int i);
+/* retrieve row scale factor */
+
+double glp_get_sjj(glp_prob *P, int j);
+/* retrieve column scale factor */
+
+void glp_scale_prob(glp_prob *P, int flags);
+/* scale problem data */
+
+void glp_unscale_prob(glp_prob *P);
+/* unscale problem data */
+
+void glp_set_row_stat(glp_prob *P, int i, int stat);
+/* set (change) row status */
+
+void glp_set_col_stat(glp_prob *P, int j, int stat);
+/* set (change) column status */
+
+void glp_std_basis(glp_prob *P);
+/* construct standard initial LP basis */
+
+void glp_adv_basis(glp_prob *P, int flags);
+/* construct advanced initial LP basis */
+
+void glp_cpx_basis(glp_prob *P);
+/* construct Bixby's initial LP basis */
+
+int glp_simplex(glp_prob *P, const glp_smcp *parm);
+/* solve LP problem with the simplex method */
+
+int glp_exact(glp_prob *P, const glp_smcp *parm);
+/* solve LP problem in exact arithmetic */
+
+void glp_init_smcp(glp_smcp *parm);
+/* initialize simplex method control parameters */
+
+int glp_get_status(glp_prob *P);
+/* retrieve generic status of basic solution */
+
+int glp_get_prim_stat(glp_prob *P);
+/* retrieve status of primal basic solution */
+
+int glp_get_dual_stat(glp_prob *P);
+/* retrieve status of dual basic solution */
+
+double glp_get_obj_val(glp_prob *P);
+/* retrieve objective value (basic solution) */
+
+int glp_get_row_stat(glp_prob *P, int i);
+/* retrieve row status */
+
+double glp_get_row_prim(glp_prob *P, int i);
+/* retrieve row primal value (basic solution) */
+
+double glp_get_row_dual(glp_prob *P, int i);
+/* retrieve row dual value (basic solution) */
+
+int glp_get_col_stat(glp_prob *P, int j);
+/* retrieve column status */
+
+double glp_get_col_prim(glp_prob *P, int j);
+/* retrieve column primal value (basic solution) */
+
+double glp_get_col_dual(glp_prob *P, int j);
+/* retrieve column dual value (basic solution) */
+
+int glp_get_unbnd_ray(glp_prob *P);
+/* determine variable causing unboundedness */
+
+int glp_interior(glp_prob *P, const glp_iptcp *parm);
+/* solve LP problem with the interior-point method */
+
+void glp_init_iptcp(glp_iptcp *parm);
+/* initialize interior-point solver control parameters */
+
+int glp_ipt_status(glp_prob *P);
+/* retrieve status of interior-point solution */
+
+double glp_ipt_obj_val(glp_prob *P);
+/* retrieve objective value (interior point) */
+
+double glp_ipt_row_prim(glp_prob *P, int i);
+/* retrieve row primal value (interior point) */
+
+double glp_ipt_row_dual(glp_prob *P, int i);
+/* retrieve row dual value (interior point) */
+
+double glp_ipt_col_prim(glp_prob *P, int j);
+/* retrieve column primal value (interior point) */
+
+double glp_ipt_col_dual(glp_prob *P, int j);
+/* retrieve column dual value (interior point) */
+
+void glp_set_col_kind(glp_prob *P, int j, int kind);
+/* set (change) column kind */
+
+int glp_get_col_kind(glp_prob *P, int j);
+/* retrieve column kind */
+
+int glp_get_num_int(glp_prob *P);
+/* retrieve number of integer columns */
+
+int glp_get_num_bin(glp_prob *P);
+/* retrieve number of binary columns */
+
+int glp_intopt(glp_prob *P, const glp_iocp *parm);
+/* solve MIP problem with the branch-and-bound method */
+
+void glp_init_iocp(glp_iocp *parm);
+/* initialize integer optimizer control parameters */
+
+int glp_mip_status(glp_prob *P);
+/* retrieve status of MIP solution */
+
+double glp_mip_obj_val(glp_prob *P);
+/* retrieve objective value (MIP solution) */
+
+double glp_mip_row_val(glp_prob *P, int i);
+/* retrieve row value (MIP solution) */
+
+double glp_mip_col_val(glp_prob *P, int j);
+/* retrieve column value (MIP solution) */
+
+int glp_print_sol(glp_prob *P, const char *fname);
+/* write basic solution in printable format */
+
+int glp_read_sol(glp_prob *P, const char *fname);
+/* read basic solution from text file */
+
+int glp_write_sol(glp_prob *P, const char *fname);
+/* write basic solution to text file */
+
+int glp_print_ranges(glp_prob *P, int len, const int list[],
+      int flags, const char *fname);
+/* print sensitivity analysis report */
+
+int glp_print_ipt(glp_prob *P, const char *fname);
+/* write interior-point solution in printable format */
+
+int glp_read_ipt(glp_prob *P, const char *fname);
+/* read interior-point solution from text file */
+
+int glp_write_ipt(glp_prob *P, const char *fname);
+/* write interior-point solution to text file */
+
+int glp_print_mip(glp_prob *P, const char *fname);
+/* write MIP solution in printable format */
+
+int glp_read_mip(glp_prob *P, const char *fname);
+/* read MIP solution from text file */
+
+int glp_write_mip(glp_prob *P, const char *fname);
+/* write MIP solution to text file */
+
+int glp_bf_exists(glp_prob *P);
+/* check if the basis factorization exists */
+
+int glp_factorize(glp_prob *P);
+/* compute the basis factorization */
+
+int glp_bf_updated(glp_prob *P);
+/* check if the basis factorization has been updated */
+
+void glp_get_bfcp(glp_prob *P, glp_bfcp *parm);
+/* retrieve basis factorization control parameters */
+
+void glp_set_bfcp(glp_prob *P, const glp_bfcp *parm);
+/* change basis factorization control parameters */
+
+int glp_get_bhead(glp_prob *P, int k);
+/* retrieve the basis header information */
+
+int glp_get_row_bind(glp_prob *P, int i);
+/* retrieve row index in the basis header */
+
+int glp_get_col_bind(glp_prob *P, int j);
+/* retrieve column index in the basis header */
+
+void glp_ftran(glp_prob *P, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+void glp_btran(glp_prob *P, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+int glp_warm_up(glp_prob *P);
+/* "warm up" LP basis */
+
+int glp_eval_tab_row(glp_prob *P, int k, int ind[], double val[]);
+/* compute row of the simplex tableau */
+
+int glp_eval_tab_col(glp_prob *P, int k, int ind[], double val[]);
+/* compute column of the simplex tableau */
+
+int glp_transform_row(glp_prob *P, int len, int ind[], double val[]);
+/* transform explicitly specified row */
+
+int glp_transform_col(glp_prob *P, int len, int ind[], double val[]);
+/* transform explicitly specified column */
+
+int glp_prim_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps);
+/* perform primal ratio test */
+
+int glp_dual_rtest(glp_prob *P, int len, const int ind[],
+      const double val[], int dir, double eps);
+/* perform dual ratio test */
+
+void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1,
+      double *value2, int *var2);
+/* analyze active bound of non-basic variable */
+
+void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1,
+      double *value1, double *coef2, int *var2, double *value2);
+/* analyze objective coefficient at basic variable */
+
+int glp_ios_reason(glp_tree *T);
+/* determine reason for calling the callback routine */
+
+glp_prob *glp_ios_get_prob(glp_tree *T);
+/* access the problem object */
+
+void glp_ios_tree_size(glp_tree *T, int *a_cnt, int *n_cnt,
+      int *t_cnt);
+/* determine size of the branch-and-bound tree */
+
+int glp_ios_curr_node(glp_tree *T);
+/* determine current active subproblem */
+
+int glp_ios_next_node(glp_tree *T, int p);
+/* determine next active subproblem */
+
+int glp_ios_prev_node(glp_tree *T, int p);
+/* determine previous active subproblem */
+
+int glp_ios_up_node(glp_tree *T, int p);
+/* determine parent subproblem */
+
+int glp_ios_node_level(glp_tree *T, int p);
+/* determine subproblem level */
+
+double glp_ios_node_bound(glp_tree *T, int p);
+/* determine subproblem local bound */
+
+int glp_ios_best_node(glp_tree *T);
+/* find active subproblem with best local bound */
+
+double glp_ios_mip_gap(glp_tree *T);
+/* compute relative MIP gap */
+
+void *glp_ios_node_data(glp_tree *T, int p);
+/* access subproblem application-specific data */
+
+void glp_ios_row_attr(glp_tree *T, int i, glp_attr *attr);
+/* retrieve additional row attributes */
+
+int glp_ios_pool_size(glp_tree *T);
+/* determine current size of the cut pool */
+
+int glp_ios_add_row(glp_tree *T,
+      const char *name, int klass, int flags, int len, const int ind[],
+      const double val[], int type, double rhs);
+/* add row (constraint) to the cut pool */
+
+void glp_ios_del_row(glp_tree *T, int i);
+/* remove row (constraint) from the cut pool */
+
+void glp_ios_clear_pool(glp_tree *T);
+/* remove all rows (constraints) from the cut pool */
+
+int glp_ios_can_branch(glp_tree *T, int j);
+/* check if can branch upon specified variable */
+
+void glp_ios_branch_upon(glp_tree *T, int j, int sel);
+/* choose variable to branch upon */
+
+void glp_ios_select_node(glp_tree *T, int p);
+/* select subproblem to continue the search */
+
+int glp_ios_heur_sol(glp_tree *T, const double x[]);
+/* provide solution found by heuristic */
+
+void glp_ios_terminate(glp_tree *T);
+/* terminate the solution process */
+
+void glp_init_mpscp(glp_mpscp *parm);
+/* initialize MPS format control parameters */
+
+int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname);
+/* read problem data in MPS format */
+
+int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname);
+/* write problem data in MPS format */
+
+void glp_init_cpxcp(glp_cpxcp *parm);
+/* initialize CPLEX LP format control parameters */
+
+int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
+/* read problem data in CPLEX LP format */
+
+int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname);
+/* write problem data in CPLEX LP format */
+
+int glp_read_prob(glp_prob *P, int flags, const char *fname);
+/* read problem data in GLPK format */
+
+int glp_write_prob(glp_prob *P, int flags, const char *fname);
+/* write problem data in GLPK format */
+
+glp_tran *glp_mpl_alloc_wksp(void);
+/* allocate the MathProg translator workspace */
+
+int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip);
+/* read and translate model section */
+
+int glp_mpl_read_data(glp_tran *tran, const char *fname);
+/* read and translate data section */
+
+int glp_mpl_generate(glp_tran *tran, const char *fname);
+/* generate the model */
+
+void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob);
+/* build LP/MIP problem instance from the model */
+
+int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol);
+/* postsolve the model */
+
+void glp_mpl_free_wksp(glp_tran *tran);
+/* free the MathProg translator workspace */
+
+int glp_main(int argc, const char *argv[]);
+/* stand-alone LP/MIP solver */
+
+/**********************************************************************/
+
+int glp_read_cnfsat(glp_prob *P, const char *fname);
+/* read CNF-SAT problem data in DIMACS format */
+
+int glp_check_cnfsat(glp_prob *P);
+/* check for CNF-SAT problem instance */
+
+int glp_write_cnfsat(glp_prob *P, const char *fname);
+/* write CNF-SAT problem data in DIMACS format */
+
+int glp_minisat1(glp_prob *P);
+/* solve CNF-SAT problem with MiniSat solver */
+
+int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound);
+/* solve integer feasibility problem */
+
+/**********************************************************************/
+
+#ifndef GLP_LONG_DEFINED
+#define GLP_LONG_DEFINED
+typedef struct { int lo, hi; } glp_long;
+/* long integer data type */
+#endif
+
+int glp_init_env(void);
+/* initialize GLPK environment */
+
+const char *glp_version(void);
+/* determine library version */
+
+int glp_free_env(void);
+/* free GLPK environment */
+
+void glp_printf(const char *fmt, ...);
+/* write formatted output to terminal */
+
+void glp_vprintf(const char *fmt, va_list arg);
+/* write formatted output to terminal */
+
+int glp_term_out(int flag);
+/* enable/disable terminal output */
+
+void glp_term_hook(int (*func)(void *info, const char *s), void *info);
+/* install hook to intercept terminal output */
+
+int glp_open_tee(const char *fname);
+/* start copying terminal output to text file */
+
+int glp_close_tee(void);
+/* stop copying terminal output to text file */
+
+#ifndef GLP_ERROR_DEFINED
+#define GLP_ERROR_DEFINED
+typedef void (*_glp_error)(const char *fmt, ...);
+#endif
+
+#define glp_error glp_error_(__FILE__, __LINE__)
+_glp_error glp_error_(const char *file, int line);
+/* display error message and terminate execution */
+
+#define glp_assert(expr) \
+      ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1)))
+void glp_assert_(const char *expr, const char *file, int line);
+/* check for logical condition */
+
+void glp_error_hook(void (*func)(void *info), void *info);
+/* install hook to intercept abnormal termination */
+
+void *glp_malloc(int size);
+/* allocate memory block */
+
+void *glp_calloc(int n, int size);
+/* allocate memory block */
+
+void glp_free(void *ptr);
+/* free memory block */
+
+void glp_mem_limit(int limit);
+/* set memory usage limit */
+
+void glp_mem_usage(int *count, int *cpeak, glp_long *total,
+      glp_long *tpeak);
+/* get memory usage information */
+
+glp_long glp_time(void);
+/* determine current universal time */
+
+double glp_difftime(glp_long t1, glp_long t0);
+/* compute difference between two time values */
+
+/**********************************************************************/
+
+#ifndef GLP_DATA_DEFINED
+#define GLP_DATA_DEFINED
+typedef struct { double _opaque_data[100]; } glp_data;
+/* plain data file */
+#endif
+
+glp_data *glp_sdf_open_file(const char *fname);
+/* open plain data file */
+
+void glp_sdf_set_jump(glp_data *data, void *jump);
+/* set up error handling */
+
+void glp_sdf_error(glp_data *data, const char *fmt, ...);
+/* print error message */
+
+void glp_sdf_warning(glp_data *data, const char *fmt, ...);
+/* print warning message */
+
+int glp_sdf_read_int(glp_data *data);
+/* read integer number */
+
+double glp_sdf_read_num(glp_data *data);
+/* read floating-point number */
+
+const char *glp_sdf_read_item(glp_data *data);
+/* read data item */
+
+const char *glp_sdf_read_text(glp_data *data);
+/* read text until end of line */
+
+int glp_sdf_line(glp_data *data);
+/* determine current line number */
+
+void glp_sdf_close_file(glp_data *data);
+/* close plain data file */
+
+/**********************************************************************/
+
+typedef struct _glp_graph glp_graph;
+typedef struct _glp_vertex glp_vertex;
+typedef struct _glp_arc glp_arc;
+
+struct _glp_graph
+{     /* graph descriptor */
+      void *pool; /* DMP *pool; */
+      /* memory pool to store graph components */
+      char *name;
+      /* graph name (1 to 255 chars); NULL means no name is assigned
+         to the graph */
+      int nv_max;
+      /* length of the vertex list (enlarged automatically) */
+      int nv;
+      /* number of vertices in the graph, 0 <= nv <= nv_max */
+      int na;
+      /* number of arcs in the graph, na >= 0 */
+      glp_vertex **v; /* glp_vertex *v[1+nv_max]; */
+      /* v[i], 1 <= i <= nv, is a pointer to i-th vertex */
+      void *index; /* AVL *index; */
+      /* vertex index to find vertices by their names; NULL means the
+         index does not exist */
+      int v_size;
+      /* size of data associated with each vertex (0 to 256 bytes) */
+      int a_size;
+      /* size of data associated with each arc (0 to 256 bytes) */
+};
+
+struct _glp_vertex
+{     /* vertex descriptor */
+      int i;
+      /* vertex ordinal number, 1 <= i <= nv */
+      char *name;
+      /* vertex name (1 to 255 chars); NULL means no name is assigned
+         to the vertex */
+      void *entry; /* AVLNODE *entry; */
+      /* pointer to corresponding entry in the vertex index; NULL means
+         that either the index does not exist or the vertex has no name
+         assigned */
+      void *data;
+      /* pointer to data associated with the vertex */
+      void *temp;
+      /* working pointer */
+      glp_arc *in;
+      /* pointer to the (unordered) list of incoming arcs */
+      glp_arc *out;
+      /* pointer to the (unordered) list of outgoing arcs */
+};
+
+struct _glp_arc
+{     /* arc descriptor */
+      glp_vertex *tail;
+      /* pointer to the tail endpoint */
+      glp_vertex *head;
+      /* pointer to the head endpoint */
+      void *data;
+      /* pointer to data associated with the arc */
+      void *temp;
+      /* working pointer */
+      glp_arc *t_prev;
+      /* pointer to previous arc having the same tail endpoint */
+      glp_arc *t_next;
+      /* pointer to next arc having the same tail endpoint */
+      glp_arc *h_prev;
+      /* pointer to previous arc having the same head endpoint */
+      glp_arc *h_next;
+      /* pointer to next arc having the same head endpoint */
+};
+
+glp_graph *glp_create_graph(int v_size, int a_size);
+/* create graph */
+
+void glp_set_graph_name(glp_graph *G, const char *name);
+/* assign (change) graph name */
+
+int glp_add_vertices(glp_graph *G, int nadd);
+/* add new vertices to graph */
+
+void glp_set_vertex_name(glp_graph *G, int i, const char *name);
+/* assign (change) vertex name */
+
+glp_arc *glp_add_arc(glp_graph *G, int i, int j);
+/* add new arc to graph */
+
+void glp_del_vertices(glp_graph *G, int ndel, const int num[]);
+/* delete vertices from graph */
+
+void glp_del_arc(glp_graph *G, glp_arc *a);
+/* delete arc from graph */
+
+void glp_erase_graph(glp_graph *G, int v_size, int a_size);
+/* erase graph content */
+
+void glp_delete_graph(glp_graph *G);
+/* delete graph */
+
+void glp_create_v_index(glp_graph *G);
+/* create vertex name index */
+
+int glp_find_vertex(glp_graph *G, const char *name);
+/* find vertex by its name */
+
+void glp_delete_v_index(glp_graph *G);
+/* delete vertex name index */
+
+int glp_read_graph(glp_graph *G, const char *fname);
+/* read graph from plain text file */
+
+int glp_write_graph(glp_graph *G, const char *fname);
+/* write graph to plain text file */
+
+void glp_mincost_lp(glp_prob *P, glp_graph *G, int names, int v_rhs,
+      int a_low, int a_cap, int a_cost);
+/* convert minimum cost flow problem to LP */
+
+int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, double *sol, int a_x, int v_pi);
+/* find minimum-cost flow with out-of-kilter algorithm */
+
+void glp_maxflow_lp(glp_prob *P, glp_graph *G, int names, int s,
+      int t, int a_cap);
+/* convert maximum flow problem to LP */
+
+int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap,
+      double *sol, int a_x, int v_cut);
+/* find maximal flow with Ford-Fulkerson algorithm */
+
+int glp_check_asnprob(glp_graph *G, int v_set);
+/* check correctness of assignment problem data */
+
+/* assignment problem formulation: */
+#define GLP_ASN_MIN        1  /* perfect matching (minimization) */
+#define GLP_ASN_MAX        2  /* perfect matching (maximization) */
+#define GLP_ASN_MMP        3  /* maximum matching */
+
+int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names,
+      int v_set, int a_cost);
+/* convert assignment problem to LP */
+
+int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost,
+      double *sol, int a_x);
+/* solve assignment problem with out-of-kilter algorithm */
+
+int glp_asnprob_hall(glp_graph *G, int v_set, int a_x);
+/* find bipartite matching of maximum cardinality */
+
+double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls);
+/* solve critical path problem */
+
+int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname);
+/* read min-cost flow problem data in DIMACS format */
+
+int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap,
+      int a_cost, const char *fname);
+/* write min-cost flow problem data in DIMACS format */
+
+int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap,
+      const char *fname);
+/* read maximum flow problem data in DIMACS format */
+
+int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap,
+      const char *fname);
+/* write maximum flow problem data in DIMACS format */
+
+int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname);
+/* read assignment problem data in DIMACS format */
+
+int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char
+      *fname);
+/* write assignment problem data in DIMACS format */
+
+int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname);
+/* read graph in DIMACS clique/coloring format */
+
+int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname);
+/* write graph in DIMACS clique/coloring format */
+
+int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+      const int parm[1+15]);
+/* Klingman's network problem generator */
+
+int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+      const int parm[1+14]);
+/* grid-like network problem generator */
+
+int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
+      const int parm[1+5]);
+/* Goldfarb's maximum flow problem generator */
+
+int glp_weak_comp(glp_graph *G, int v_num);
+/* find all weakly connected components of graph */
+
+int glp_strong_comp(glp_graph *G, int v_num);
+/* find all strongly connected components of graph */
+
+int glp_top_sort(glp_graph *G, int v_num);
+/* topological sorting of acyclic digraph */
+
+int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set);
+/* find maximum weight clique with exact algorithm */
+
+/***********************************************************************
+*  NOTE: All symbols defined below are obsolete and kept here only for
+*        backward compatibility.
+***********************************************************************/
+
+#define LPX glp_prob
+
+/* problem class: */
+#define LPX_LP          100   /* linear programming (LP) */
+#define LPX_MIP         101   /* mixed integer programming (MIP) */
+
+/* type of auxiliary/structural variable: */
+#define LPX_FR          110   /* free variable */
+#define LPX_LO          111   /* variable with lower bound */
+#define LPX_UP          112   /* variable with upper bound */
+#define LPX_DB          113   /* double-bounded variable */
+#define LPX_FX          114   /* fixed variable */
+
+/* optimization direction flag: */
+#define LPX_MIN         120   /* minimization */
+#define LPX_MAX         121   /* maximization */
+
+/* status of primal basic solution: */
+#define LPX_P_UNDEF     132   /* primal solution is undefined */
+#define LPX_P_FEAS      133   /* solution is primal feasible */
+#define LPX_P_INFEAS    134   /* solution is primal infeasible */
+#define LPX_P_NOFEAS    135   /* no primal feasible solution exists */
+
+/* status of dual basic solution: */
+#define LPX_D_UNDEF     136   /* dual solution is undefined */
+#define LPX_D_FEAS      137   /* solution is dual feasible */
+#define LPX_D_INFEAS    138   /* solution is dual infeasible */
+#define LPX_D_NOFEAS    139   /* no dual feasible solution exists */
+
+/* status of auxiliary/structural variable: */
+#define LPX_BS          140   /* basic variable */
+#define LPX_NL          141   /* non-basic variable on lower bound */
+#define LPX_NU          142   /* non-basic variable on upper bound */
+#define LPX_NF          143   /* non-basic free variable */
+#define LPX_NS          144   /* non-basic fixed variable */
+
+/* status of interior-point solution: */
+#define LPX_T_UNDEF     150   /* interior solution is undefined */
+#define LPX_T_OPT       151   /* interior solution is optimal */
+
+/* kind of structural variable: */
+#define LPX_CV          160   /* continuous variable */
+#define LPX_IV          161   /* integer variable */
+
+/* status of integer solution: */
+#define LPX_I_UNDEF     170   /* integer solution is undefined */
+#define LPX_I_OPT       171   /* integer solution is optimal */
+#define LPX_I_FEAS      172   /* integer solution is feasible */
+#define LPX_I_NOFEAS    173   /* no integer solution exists */
+
+/* status codes reported by the routine lpx_get_status: */
+#define LPX_OPT         180   /* optimal */
+#define LPX_FEAS        181   /* feasible */
+#define LPX_INFEAS      182   /* infeasible */
+#define LPX_NOFEAS      183   /* no feasible */
+#define LPX_UNBND       184   /* unbounded */
+#define LPX_UNDEF       185   /* undefined */
+
+/* exit codes returned by solver routines: */
+#define LPX_E_OK        200   /* success */
+#define LPX_E_EMPTY     201   /* empty problem */
+#define LPX_E_BADB      202   /* invalid initial basis */
+#define LPX_E_INFEAS    203   /* infeasible initial solution */
+#define LPX_E_FAULT     204   /* unable to start the search */
+#define LPX_E_OBJLL     205   /* objective lower limit reached */
+#define LPX_E_OBJUL     206   /* objective upper limit reached */
+#define LPX_E_ITLIM     207   /* iterations limit exhausted */
+#define LPX_E_TMLIM     208   /* time limit exhausted */
+#define LPX_E_NOFEAS    209   /* no feasible solution */
+#define LPX_E_INSTAB    210   /* numerical instability */
+#define LPX_E_SING      211   /* problems with basis matrix */
+#define LPX_E_NOCONV    212   /* no convergence (interior) */
+#define LPX_E_NOPFS     213   /* no primal feas. sol. (LP presolver) */
+#define LPX_E_NODFS     214   /* no dual feas. sol. (LP presolver) */
+#define LPX_E_MIPGAP    215   /* relative mip gap tolerance reached */
+
+/* control parameter identifiers: */
+#define LPX_K_MSGLEV    300   /* lp->msg_lev */
+#define LPX_K_SCALE     301   /* lp->scale */
+#define LPX_K_DUAL      302   /* lp->dual */
+#define LPX_K_PRICE     303   /* lp->price */
+#define LPX_K_RELAX     304   /* lp->relax */
+#define LPX_K_TOLBND    305   /* lp->tol_bnd */
+#define LPX_K_TOLDJ     306   /* lp->tol_dj */
+#define LPX_K_TOLPIV    307   /* lp->tol_piv */
+#define LPX_K_ROUND     308   /* lp->round */
+#define LPX_K_OBJLL     309   /* lp->obj_ll */
+#define LPX_K_OBJUL     310   /* lp->obj_ul */
+#define LPX_K_ITLIM     311   /* lp->it_lim */
+#define LPX_K_ITCNT     312   /* lp->it_cnt */
+#define LPX_K_TMLIM     313   /* lp->tm_lim */
+#define LPX_K_OUTFRQ    314   /* lp->out_frq */
+#define LPX_K_OUTDLY    315   /* lp->out_dly */
+#define LPX_K_BRANCH    316   /* lp->branch */
+#define LPX_K_BTRACK    317   /* lp->btrack */
+#define LPX_K_TOLINT    318   /* lp->tol_int */
+#define LPX_K_TOLOBJ    319   /* lp->tol_obj */
+#define LPX_K_MPSINFO   320   /* lp->mps_info */
+#define LPX_K_MPSOBJ    321   /* lp->mps_obj */
+#define LPX_K_MPSORIG   322   /* lp->mps_orig */
+#define LPX_K_MPSWIDE   323   /* lp->mps_wide */
+#define LPX_K_MPSFREE   324   /* lp->mps_free */
+#define LPX_K_MPSSKIP   325   /* lp->mps_skip */
+#define LPX_K_LPTORIG   326   /* lp->lpt_orig */
+#define LPX_K_PRESOL    327   /* lp->presol */
+#define LPX_K_BINARIZE  328   /* lp->binarize */
+#define LPX_K_USECUTS   329   /* lp->use_cuts */
+#define LPX_K_BFTYPE    330   /* lp->bfcp->type */
+#define LPX_K_MIPGAP    331   /* lp->mip_gap */
+
+#define LPX_C_COVER     0x01  /* mixed cover cuts */
+#define LPX_C_CLIQUE    0x02  /* clique cuts */
+#define LPX_C_GOMORY    0x04  /* Gomory's mixed integer cuts */
+#define LPX_C_MIR       0x08  /* mixed integer rounding cuts */
+#define LPX_C_ALL       0xFF  /* all cuts */
+
+typedef struct
+{     /* this structure contains results reported by the routines which
+         checks Karush-Kuhn-Tucker conditions (for details see comments
+         to those routines) */
+      /*--------------------------------------------------------------*/
+      /* xR - A * xS = 0 (KKT.PE) */
+      double pe_ae_max;
+      /* largest absolute error */
+      int    pe_ae_row;
+      /* number of row with largest absolute error */
+      double pe_re_max;
+      /* largest relative error */
+      int    pe_re_row;
+      /* number of row with largest relative error */
+      int    pe_quality;
+      /* quality of primal solution:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - primal solution is wrong */
+      /*--------------------------------------------------------------*/
+      /* l[k] <= x[k] <= u[k] (KKT.PB) */
+      double pb_ae_max;
+      /* largest absolute error */
+      int    pb_ae_ind;
+      /* number of variable with largest absolute error */
+      double pb_re_max;
+      /* largest relative error */
+      int    pb_re_ind;
+      /* number of variable with largest relative error */
+      int    pb_quality;
+      /* quality of primal feasibility:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - primal solution is infeasible */
+      /*--------------------------------------------------------------*/
+      /* A' * (dR - cR) + (dS - cS) = 0 (KKT.DE) */
+      double de_ae_max;
+      /* largest absolute error */
+      int    de_ae_col;
+      /* number of column with largest absolute error */
+      double de_re_max;
+      /* largest relative error */
+      int    de_re_col;
+      /* number of column with largest relative error */
+      int    de_quality;
+      /* quality of dual solution:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - dual solution is wrong */
+      /*--------------------------------------------------------------*/
+      /* d[k] >= 0 or d[k] <= 0 (KKT.DB) */
+      double db_ae_max;
+      /* largest absolute error */
+      int    db_ae_ind;
+      /* number of variable with largest absolute error */
+      double db_re_max;
+      /* largest relative error */
+      int    db_re_ind;
+      /* number of variable with largest relative error */
+      int    db_quality;
+      /* quality of dual feasibility:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - dual solution is infeasible */
+      /*--------------------------------------------------------------*/
+      /* (x[k] - bound of x[k]) * d[k] = 0 (KKT.CS) */
+      double cs_ae_max;
+      /* largest absolute error */
+      int    cs_ae_ind;
+      /* number of variable with largest absolute error */
+      double cs_re_max;
+      /* largest relative error */
+      int    cs_re_ind;
+      /* number of variable with largest relative error */
+      int    cs_quality;
+      /* quality of complementary slackness:
+         'H' - high
+         'M' - medium
+         'L' - low
+         '?' - primal and dual solutions are not complementary */
+} LPXKKT;
+
+#define lpx_create_prob _glp_lpx_create_prob
+LPX *lpx_create_prob(void);
+/* create problem object */
+
+#define lpx_set_prob_name _glp_lpx_set_prob_name
+void lpx_set_prob_name(LPX *lp, const char *name);
+/* assign (change) problem name */
+
+#define lpx_set_obj_name _glp_lpx_set_obj_name
+void lpx_set_obj_name(LPX *lp, const char *name);
+/* assign (change) objective function name */
+
+#define lpx_set_obj_dir _glp_lpx_set_obj_dir
+void lpx_set_obj_dir(LPX *lp, int dir);
+/* set (change) optimization direction flag */
+
+#define lpx_add_rows _glp_lpx_add_rows
+int lpx_add_rows(LPX *lp, int nrs);
+/* add new rows to problem object */
+
+#define lpx_add_cols _glp_lpx_add_cols
+int lpx_add_cols(LPX *lp, int ncs);
+/* add new columns to problem object */
+
+#define lpx_set_row_name _glp_lpx_set_row_name
+void lpx_set_row_name(LPX *lp, int i, const char *name);
+/* assign (change) row name */
+
+#define lpx_set_col_name _glp_lpx_set_col_name
+void lpx_set_col_name(LPX *lp, int j, const char *name);
+/* assign (change) column name */
+
+#define lpx_set_row_bnds _glp_lpx_set_row_bnds
+void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub);
+/* set (change) row bounds */
+
+#define lpx_set_col_bnds _glp_lpx_set_col_bnds
+void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub);
+/* set (change) column bounds */
+
+#define lpx_set_obj_coef _glp_lpx_set_obj_coef
+void lpx_set_obj_coef(glp_prob *lp, int j, double coef);
+/* set (change) obj. coefficient or constant term */
+
+#define lpx_set_mat_row _glp_lpx_set_mat_row
+void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
+      const double val[]);
+/* set (replace) row of the constraint matrix */
+
+#define lpx_set_mat_col _glp_lpx_set_mat_col
+void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
+      const double val[]);
+/* set (replace) column of the constraint matrix */
+
+#define lpx_load_matrix _glp_lpx_load_matrix
+void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
+      const double ar[]);
+/* load (replace) the whole constraint matrix */
+
+#define lpx_del_rows _glp_lpx_del_rows
+void lpx_del_rows(LPX *lp, int nrs, const int num[]);
+/* delete specified rows from problem object */
+
+#define lpx_del_cols _glp_lpx_del_cols
+void lpx_del_cols(LPX *lp, int ncs, const int num[]);
+/* delete specified columns from problem object */
+
+#define lpx_delete_prob _glp_lpx_delete_prob
+void lpx_delete_prob(LPX *lp);
+/* delete problem object */
+
+#define lpx_get_prob_name _glp_lpx_get_prob_name
+const char *lpx_get_prob_name(LPX *lp);
+/* retrieve problem name */
+
+#define lpx_get_obj_name _glp_lpx_get_obj_name
+const char *lpx_get_obj_name(LPX *lp);
+/* retrieve objective function name */
+
+#define lpx_get_obj_dir _glp_lpx_get_obj_dir
+int lpx_get_obj_dir(LPX *lp);
+/* retrieve optimization direction flag */
+
+#define lpx_get_num_rows _glp_lpx_get_num_rows
+int lpx_get_num_rows(LPX *lp);
+/* retrieve number of rows */
+
+#define lpx_get_num_cols _glp_lpx_get_num_cols
+int lpx_get_num_cols(LPX *lp);
+/* retrieve number of columns */
+
+#define lpx_get_row_name _glp_lpx_get_row_name
+const char *lpx_get_row_name(LPX *lp, int i);
+/* retrieve row name */
+
+#define lpx_get_col_name _glp_lpx_get_col_name
+const char *lpx_get_col_name(LPX *lp, int j);
+/* retrieve column name */
+
+#define lpx_get_row_type _glp_lpx_get_row_type
+int lpx_get_row_type(LPX *lp, int i);
+/* retrieve row type */
+
+#define lpx_get_row_lb _glp_lpx_get_row_lb
+double lpx_get_row_lb(LPX *lp, int i);
+/* retrieve row lower bound */
+
+#define lpx_get_row_ub _glp_lpx_get_row_ub
+double lpx_get_row_ub(LPX *lp, int i);
+/* retrieve row upper bound */
+
+#define lpx_get_row_bnds _glp_lpx_get_row_bnds
+void lpx_get_row_bnds(LPX *lp, int i, int *typx, double *lb,
+      double *ub);
+/* retrieve row bounds */
+
+#define lpx_get_col_type _glp_lpx_get_col_type
+int lpx_get_col_type(LPX *lp, int j);
+/* retrieve column type */
+
+#define lpx_get_col_lb _glp_lpx_get_col_lb
+double lpx_get_col_lb(LPX *lp, int j);
+/* retrieve column lower bound */
+
+#define lpx_get_col_ub _glp_lpx_get_col_ub
+double lpx_get_col_ub(LPX *lp, int j);
+/* retrieve column upper bound */
+
+#define lpx_get_col_bnds _glp_lpx_get_col_bnds
+void lpx_get_col_bnds(LPX *lp, int j, int *typx, double *lb,
+      double *ub);
+/* retrieve column bounds */
+
+#define lpx_get_obj_coef _glp_lpx_get_obj_coef
+double lpx_get_obj_coef(LPX *lp, int j);
+/* retrieve obj. coefficient or constant term */
+
+#define lpx_get_num_nz _glp_lpx_get_num_nz
+int lpx_get_num_nz(LPX *lp);
+/* retrieve number of constraint coefficients */
+
+#define lpx_get_mat_row _glp_lpx_get_mat_row
+int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[]);
+/* retrieve row of the constraint matrix */
+
+#define lpx_get_mat_col _glp_lpx_get_mat_col
+int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[]);
+/* retrieve column of the constraint matrix */
+
+#define lpx_create_index _glp_lpx_create_index
+void lpx_create_index(LPX *lp);
+/* create the name index */
+
+#define lpx_find_row _glp_lpx_find_row
+int lpx_find_row(LPX *lp, const char *name);
+/* find row by its name */
+
+#define lpx_find_col _glp_lpx_find_col
+int lpx_find_col(LPX *lp, const char *name);
+/* find column by its name */
+
+#define lpx_delete_index _glp_lpx_delete_index
+void lpx_delete_index(LPX *lp);
+/* delete the name index */
+
+#define lpx_scale_prob _glp_lpx_scale_prob
+void lpx_scale_prob(LPX *lp);
+/* scale problem data */
+
+#define lpx_unscale_prob _glp_lpx_unscale_prob
+void lpx_unscale_prob(LPX *lp);
+/* unscale problem data */
+
+#define lpx_set_row_stat _glp_lpx_set_row_stat
+void lpx_set_row_stat(LPX *lp, int i, int stat);
+/* set (change) row status */
+
+#define lpx_set_col_stat _glp_lpx_set_col_stat
+void lpx_set_col_stat(LPX *lp, int j, int stat);
+/* set (change) column status */
+
+#define lpx_std_basis _glp_lpx_std_basis
+void lpx_std_basis(LPX *lp);
+/* construct standard initial LP basis */
+
+#define lpx_adv_basis _glp_lpx_adv_basis
+void lpx_adv_basis(LPX *lp);
+/* construct advanced initial LP basis */
+
+#define lpx_cpx_basis _glp_lpx_cpx_basis
+void lpx_cpx_basis(LPX *lp);
+/* construct Bixby's initial LP basis */
+
+#define lpx_simplex _glp_lpx_simplex
+int lpx_simplex(LPX *lp);
+/* easy-to-use driver to the simplex method */
+
+#define lpx_exact _glp_lpx_exact
+int lpx_exact(LPX *lp);
+/* easy-to-use driver to the exact simplex method */
+
+#define lpx_get_status _glp_lpx_get_status
+int lpx_get_status(LPX *lp);
+/* retrieve generic status of basic solution */
+
+#define lpx_get_prim_stat _glp_lpx_get_prim_stat
+int lpx_get_prim_stat(LPX *lp);
+/* retrieve primal status of basic solution */
+
+#define lpx_get_dual_stat _glp_lpx_get_dual_stat
+int lpx_get_dual_stat(LPX *lp);
+/* retrieve dual status of basic solution */
+
+#define lpx_get_obj_val _glp_lpx_get_obj_val
+double lpx_get_obj_val(LPX *lp);
+/* retrieve objective value (basic solution) */
+
+#define lpx_get_row_stat _glp_lpx_get_row_stat
+int lpx_get_row_stat(LPX *lp, int i);
+/* retrieve row status (basic solution) */
+
+#define lpx_get_row_prim _glp_lpx_get_row_prim
+double lpx_get_row_prim(LPX *lp, int i);
+/* retrieve row primal value (basic solution) */
+
+#define lpx_get_row_dual _glp_lpx_get_row_dual
+double lpx_get_row_dual(LPX *lp, int i);
+/* retrieve row dual value (basic solution) */
+
+#define lpx_get_row_info _glp_lpx_get_row_info
+void lpx_get_row_info(LPX *lp, int i, int *tagx, double *vx,
+      double *dx);
+/* obtain row solution information */
+
+#define lpx_get_col_stat _glp_lpx_get_col_stat
+int lpx_get_col_stat(LPX *lp, int j);
+/* retrieve column status (basic solution) */
+
+#define lpx_get_col_prim _glp_lpx_get_col_prim
+double lpx_get_col_prim(LPX *lp, int j);
+/* retrieve column primal value (basic solution) */
+
+#define lpx_get_col_dual _glp_lpx_get_col_dual
+double lpx_get_col_dual(glp_prob *lp, int j);
+/* retrieve column dual value (basic solution) */
+
+#define lpx_get_col_info _glp_lpx_get_col_info
+void lpx_get_col_info(LPX *lp, int j, int *tagx, double *vx,
+      double *dx);
+/* obtain column solution information (obsolete) */
+
+#define lpx_get_ray_info _glp_lpx_get_ray_info
+int lpx_get_ray_info(LPX *lp);
+/* determine what causes primal unboundness */
+
+#define lpx_check_kkt _glp_lpx_check_kkt
+void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt);
+/* check Karush-Kuhn-Tucker conditions */
+
+#define lpx_warm_up _glp_lpx_warm_up
+int lpx_warm_up(LPX *lp);
+/* "warm up" LP basis */
+
+#define lpx_eval_tab_row _glp_lpx_eval_tab_row
+int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[]);
+/* compute row of the simplex table */
+
+#define lpx_eval_tab_col _glp_lpx_eval_tab_col
+int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[]);
+/* compute column of the simplex table */
+
+#define lpx_transform_row _glp_lpx_transform_row
+int lpx_transform_row(LPX *lp, int len, int ind[], double val[]);
+/* transform explicitly specified row */
+
+#define lpx_transform_col _glp_lpx_transform_col
+int lpx_transform_col(LPX *lp, int len, int ind[], double val[]);
+/* transform explicitly specified column */
+
+#define lpx_prim_ratio_test _glp_lpx_prim_ratio_test
+int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol);
+/* perform primal ratio test */
+
+#define lpx_dual_ratio_test _glp_lpx_dual_ratio_test
+int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol);
+/* perform dual ratio test */
+
+#define lpx_interior _glp_lpx_interior
+int lpx_interior(LPX *lp);
+/* easy-to-use driver to the interior point method */
+
+#define lpx_ipt_status _glp_lpx_ipt_status
+int lpx_ipt_status(LPX *lp);
+/* retrieve status of interior-point solution */
+
+#define lpx_ipt_obj_val _glp_lpx_ipt_obj_val
+double lpx_ipt_obj_val(LPX *lp);
+/* retrieve objective value (interior point) */
+
+#define lpx_ipt_row_prim _glp_lpx_ipt_row_prim
+double lpx_ipt_row_prim(LPX *lp, int i);
+/* retrieve row primal value (interior point) */
+
+#define lpx_ipt_row_dual _glp_lpx_ipt_row_dual
+double lpx_ipt_row_dual(LPX *lp, int i);
+/* retrieve row dual value (interior point) */
+
+#define lpx_ipt_col_prim _glp_lpx_ipt_col_prim
+double lpx_ipt_col_prim(LPX *lp, int j);
+/* retrieve column primal value (interior point) */
+
+#define lpx_ipt_col_dual _glp_lpx_ipt_col_dual
+double lpx_ipt_col_dual(LPX *lp, int j);
+/* retrieve column dual value (interior point) */
+
+#define lpx_set_class _glp_lpx_set_class
+void lpx_set_class(LPX *lp, int klass);
+/* set problem class */
+
+#define lpx_get_class _glp_lpx_get_class
+int lpx_get_class(LPX *lp);
+/* determine problem klass */
+
+#define lpx_set_col_kind _glp_lpx_set_col_kind
+void lpx_set_col_kind(LPX *lp, int j, int kind);
+/* set (change) column kind */
+
+#define lpx_get_col_kind _glp_lpx_get_col_kind
+int lpx_get_col_kind(LPX *lp, int j);
+/* retrieve column kind */
+
+#define lpx_get_num_int _glp_lpx_get_num_int
+int lpx_get_num_int(LPX *lp);
+/* retrieve number of integer columns */
+
+#define lpx_get_num_bin _glp_lpx_get_num_bin
+int lpx_get_num_bin(LPX *lp);
+/* retrieve number of binary columns */
+
+#define lpx_integer _glp_lpx_integer
+int lpx_integer(LPX *lp);
+/* easy-to-use driver to the branch-and-bound method */
+
+#define lpx_intopt _glp_lpx_intopt
+int lpx_intopt(LPX *lp);
+/* easy-to-use driver to the branch-and-bound method */
+
+#define lpx_mip_status _glp_lpx_mip_status
+int lpx_mip_status(LPX *lp);
+/* retrieve status of MIP solution */
+
+#define lpx_mip_obj_val _glp_lpx_mip_obj_val
+double lpx_mip_obj_val(LPX *lp);
+/* retrieve objective value (MIP solution) */
+
+#define lpx_mip_row_val _glp_lpx_mip_row_val
+double lpx_mip_row_val(LPX *lp, int i);
+/* retrieve row value (MIP solution) */
+
+#define lpx_mip_col_val _glp_lpx_mip_col_val
+double lpx_mip_col_val(LPX *lp, int j);
+/* retrieve column value (MIP solution) */
+
+#define lpx_check_int _glp_lpx_check_int
+void lpx_check_int(LPX *lp, LPXKKT *kkt);
+/* check integer feasibility conditions */
+
+#define lpx_reset_parms _glp_lpx_reset_parms
+void lpx_reset_parms(LPX *lp);
+/* reset control parameters to default values */
+
+#define lpx_set_int_parm _glp_lpx_set_int_parm
+void lpx_set_int_parm(LPX *lp, int parm, int val);
+/* set (change) integer control parameter */
+
+#define lpx_get_int_parm _glp_lpx_get_int_parm
+int lpx_get_int_parm(LPX *lp, int parm);
+/* query integer control parameter */
+
+#define lpx_set_real_parm _glp_lpx_set_real_parm
+void lpx_set_real_parm(LPX *lp, int parm, double val);
+/* set (change) real control parameter */
+
+#define lpx_get_real_parm _glp_lpx_get_real_parm
+double lpx_get_real_parm(LPX *lp, int parm);
+/* query real control parameter */
+
+#define lpx_read_mps _glp_lpx_read_mps
+LPX *lpx_read_mps(const char *fname);
+/* read problem data in fixed MPS format */
+
+#define lpx_write_mps _glp_lpx_write_mps
+int lpx_write_mps(LPX *lp, const char *fname);
+/* write problem data in fixed MPS format */
+
+#define lpx_read_bas _glp_lpx_read_bas
+int lpx_read_bas(LPX *lp, const char *fname);
+/* read LP basis in fixed MPS format */
+
+#define lpx_write_bas _glp_lpx_write_bas
+int lpx_write_bas(LPX *lp, const char *fname);
+/* write LP basis in fixed MPS format */
+
+#define lpx_read_freemps _glp_lpx_read_freemps
+LPX *lpx_read_freemps(const char *fname);
+/* read problem data in free MPS format */
+
+#define lpx_write_freemps _glp_lpx_write_freemps
+int lpx_write_freemps(LPX *lp, const char *fname);
+/* write problem data in free MPS format */
+
+#define lpx_read_cpxlp _glp_lpx_read_cpxlp
+LPX *lpx_read_cpxlp(const char *fname);
+/* read problem data in CPLEX LP format */
+
+#define lpx_write_cpxlp _glp_lpx_write_cpxlp
+int lpx_write_cpxlp(LPX *lp, const char *fname);
+/* write problem data in CPLEX LP format */
+
+#define lpx_read_model _glp_lpx_read_model
+LPX *lpx_read_model(const char *model, const char *data,
+      const char *output);
+/* read LP/MIP model written in GNU MathProg language */
+
+#define lpx_print_prob _glp_lpx_print_prob
+int lpx_print_prob(LPX *lp, const char *fname);
+/* write problem data in plain text format */
+
+#define lpx_print_sol _glp_lpx_print_sol
+int lpx_print_sol(LPX *lp, const char *fname);
+/* write LP problem solution in printable format */
+
+#define lpx_print_sens_bnds _glp_lpx_print_sens_bnds
+int lpx_print_sens_bnds(LPX *lp, const char *fname);
+/* write bounds sensitivity information */
+
+#define lpx_print_ips _glp_lpx_print_ips
+int lpx_print_ips(LPX *lp, const char *fname);
+/* write interior point solution in printable format */
+
+#define lpx_print_mip _glp_lpx_print_mip
+int lpx_print_mip(LPX *lp, const char *fname);
+/* write MIP problem solution in printable format */
+
+#define lpx_is_b_avail _glp_lpx_is_b_avail
+int lpx_is_b_avail(LPX *lp);
+/* check if LP basis is available */
+
+#define lpx_write_pb _glp_lpx_write_pb
+int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+      int binarize);
+/* write problem data in (normalized) OPB format */
+
+#define lpx_main _glp_lpx_main
+int lpx_main(int argc, const char *argv[]);
+/* stand-alone LP/MIP solver */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glplib.h
===================================================================
--- deps/glpk/src/glplib.h	(revision 9)
+++ deps/glpk/src/glplib.h	(revision 9)
@@ -0,0 +1,135 @@
+/* glplib.h (miscellaneous library routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPLIB_H
+#define GLPLIB_H
+
+#define bigmul _glp_lib_bigmul
+void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
+/* multiply unsigned integer numbers of arbitrary precision */
+
+#define bigdiv _glp_lib_bigdiv
+void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
+/* divide unsigned integer numbers of arbitrary precision */
+
+#ifndef GLP_LONG_DEFINED
+#define GLP_LONG_DEFINED
+typedef struct { int lo, hi; } glp_long;
+/* long integer data type */
+#endif
+
+typedef struct { glp_long quot, rem; } glp_ldiv;
+/* result of long integer division */
+
+#define xlset _glp_lib_xlset
+glp_long xlset(int x);
+/* expand integer to long integer */
+
+#define xlneg _glp_lib_xlneg
+glp_long xlneg(glp_long x);
+/* negate long integer */
+
+#define xladd _glp_lib_xladd
+glp_long xladd(glp_long x, glp_long y);
+/* add long integers */
+
+#define xlsub _glp_lib_xlsub
+glp_long xlsub(glp_long x, glp_long y);
+/* subtract long integers */
+
+#define xlcmp _glp_lib_xlcmp
+int xlcmp(glp_long x, glp_long y);
+/* compare long integers */
+
+#define xlmul _glp_lib_xlmul
+glp_long xlmul(glp_long x, glp_long y);
+/* multiply long integers */
+
+#define xldiv _glp_lib_xldiv
+glp_ldiv xldiv(glp_long x, glp_long y);
+/* divide long integers */
+
+#define xltod _glp_lib_xltod
+double xltod(glp_long x);
+/* convert long integer to double */
+
+#define xltoa _glp_lib_xltoa
+char *xltoa(glp_long x, char *s);
+/* convert long integer to character string */
+
+#define str2int _glp_lib_str2int
+int str2int(const char *str, int *val);
+/* convert character string to value of int type */
+
+#define str2num _glp_lib_str2num
+int str2num(const char *str, double *val);
+/* convert character string to value of double type */
+
+#define strspx _glp_lib_strspx
+char *strspx(char *str);
+/* remove all spaces from character string */
+
+#define strtrim _glp_lib_strtrim
+char *strtrim(char *str);
+/* remove trailing spaces from character string */
+
+#define strrev _glp_lib_strrev
+char *strrev(char *s);
+/* reverse character string */
+
+#define gcd _glp_lib_gcd
+int gcd(int x, int y);
+/* find greatest common divisor of two integers */
+
+#define gcdn _glp_lib_gcdn
+int gcdn(int n, int x[]);
+/* find greatest common divisor of n integers */
+
+#define lcm _glp_lib_lcm
+int lcm(int x, int y);
+/* find least common multiple of two integers */
+
+#define lcmn _glp_lib_lcmn
+int lcmn(int n, int x[]);
+/* find least common multiple of n integers */
+
+#define round2n _glp_lib_round2n
+double round2n(double x);
+/* round floating-point number to nearest power of two */
+
+#define fp2rat _glp_lib_fp2rat
+int fp2rat(double x, double eps, double *p, double *q);
+/* convert floating-point number to rational number */
+
+#define jday _glp_lib_jday
+int jday(int d, int m, int y);
+/* convert calendar date to Julian day number */
+
+#define jdate _glp_lib_jdate
+int jdate(int j, int *d, int *m, int *y);
+/* convert Julian day number to calendar date */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glplib01.c
===================================================================
--- deps/glpk/src/glplib01.c	(revision 9)
+++ deps/glpk/src/glplib01.c	(revision 9)
@@ -0,0 +1,287 @@
+/* glplib01.c (bignum arithmetic) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glplib.h"
+
+/***********************************************************************
+*  Two routines below are intended to multiply and divide unsigned
+*  integer numbers of arbitrary precision.
+* 
+*  The routines assume that an unsigned integer number is represented in
+*  the positional numeral system with the base 2^16 = 65536, i.e. each
+*  "digit" of the number is in the range [0, 65535] and represented as
+*  a 16-bit value of the unsigned short type. In other words, a number x
+*  has the following representation:
+* 
+*         n-1
+*     x = sum d[j] * 65536^j,
+*         j=0
+* 
+*  where n is the number of places (positions), and d[j] is j-th "digit"
+*  of x, 0 <= d[j] <= 65535.
+***********************************************************************/
+
+/***********************************************************************
+*  NAME
+*
+*  bigmul - multiply unsigned integer numbers of arbitrary precision
+* 
+*  SYNOPSIS
+* 
+*  #include "glplib.h"
+*  void bigmul(int n, int m, unsigned short x[], unsigned short y[]);
+* 
+*  DESCRIPTION
+* 
+*  The routine bigmul multiplies unsigned integer numbers of arbitrary
+*  precision.
+* 
+*  n is the number of digits of multiplicand, n >= 1;
+* 
+*  m is the number of digits of multiplier, m >= 1;
+* 
+*  x is an array containing digits of the multiplicand in elements
+*  x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are
+*  ignored on entry.
+* 
+*  y is an array containing digits of the multiplier in elements y[0],
+*  y[1], ..., y[m-1].
+* 
+*  On exit digits of the product are stored in elements x[0], x[1], ...,
+*  x[n+m-1]. The array y is not changed. */
+
+void bigmul(int n, int m, unsigned short x[], unsigned short y[])
+{     int i, j;
+      unsigned int t;
+      xassert(n >= 1);
+      xassert(m >= 1);
+      for (j = 0; j < m; j++) x[j] = 0;
+      for (i = 0; i < n; i++)
+      {  if (x[i+m])
+         {  t = 0;
+            for (j = 0; j < m; j++)
+            {  t += (unsigned int)x[i+m] * (unsigned int)y[j] +
+                    (unsigned int)x[i+j];
+               x[i+j] = (unsigned short)t;
+               t >>= 16;
+            }
+            x[i+m] = (unsigned short)t;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  bigdiv - divide unsigned integer numbers of arbitrary precision
+* 
+*  SYNOPSIS
+* 
+*  #include "glplib.h"
+*  void bigdiv(int n, int m, unsigned short x[], unsigned short y[]);
+* 
+*  DESCRIPTION
+* 
+*  The routine bigdiv divides one unsigned integer number of arbitrary
+*  precision by another with the algorithm described in [1].
+* 
+*  n is the difference between the number of digits of dividend and the
+*  number of digits of divisor, n >= 0.
+* 
+*  m is the number of digits of divisor, m >= 1.
+* 
+*  x is an array containing digits of the dividend in elements x[0],
+*  x[1], ..., x[n+m-1].
+* 
+*  y is an array containing digits of the divisor in elements y[0],
+*  y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero.
+* 
+*  On exit n+1 digits of the quotient are stored in elements x[m],
+*  x[m+1], ..., x[n+m], and m digits of the remainder are stored in
+*  elements x[0], x[1], ..., x[m-1]. The array y is changed but then
+*  restored.
+*
+*  REFERENCES
+*
+*  1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical
+*  Algorithms. Stanford University, 1969. */
+
+void bigdiv(int n, int m, unsigned short x[], unsigned short y[])
+{     int i, j;
+      unsigned int t;
+      unsigned short d, q, r;
+      xassert(n >= 0);
+      xassert(m >= 1);
+      xassert(y[m-1] != 0);
+      /* special case when divisor has the only digit */
+      if (m == 1)
+      {  d = 0;
+         for (i = n; i >= 0; i--)
+         {  t = ((unsigned int)d << 16) + (unsigned int)x[i];
+            x[i+1] = (unsigned short)(t / y[0]);
+            d = (unsigned short)(t % y[0]);
+         }
+         x[0] = d;
+         goto done;
+      }
+      /* multiply dividend and divisor by a normalizing coefficient in
+         order to provide the condition y[m-1] >= base / 2 */
+      d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1));
+      if (d == 1)
+         x[n+m] = 0;
+      else
+      {  t = 0;
+         for (i = 0; i < n+m; i++)
+         {  t += (unsigned int)x[i] * (unsigned int)d;
+            x[i] = (unsigned short)t;
+            t >>= 16;
+         }
+         x[n+m] = (unsigned short)t;
+         t = 0;
+         for (j = 0; j < m; j++)
+         {  t += (unsigned int)y[j] * (unsigned int)d;
+            y[j] = (unsigned short)t;
+            t >>= 16;
+         }
+      }
+      /* main loop */
+      for (i = n; i >= 0; i--)
+      {  /* estimate and correct the current digit of quotient */
+         if (x[i+m] < y[m-1])
+         {  t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1];
+            q = (unsigned short)(t / (unsigned int)y[m-1]);
+            r = (unsigned short)(t % (unsigned int)y[m-1]);
+            if (q == 0) goto putq; else goto test;
+         }
+         q = 0;
+         r = x[i+m-1];
+decr:    q--; /* if q = 0 then q-- = 0xFFFF */
+         t = (unsigned int)r + (unsigned int)y[m-1];
+         r = (unsigned short)t;
+         if (t > 0xFFFF) goto msub;
+test:    t = (unsigned int)y[m-2] * (unsigned int)q;
+         if ((unsigned short)(t >> 16) > r) goto decr;
+         if ((unsigned short)(t >> 16) < r) goto msub;
+         if ((unsigned short)t > x[i+m-2]) goto decr;
+msub:    /* now subtract divisor multiplied by the current digit of
+            quotient from the current dividend */
+         if (q == 0) goto putq;
+         t = 0;
+         for (j = 0; j < m; j++)
+         {  t += (unsigned int)y[j] * (unsigned int)q;
+            if (x[i+j] < (unsigned short)t) t += 0x10000;
+            x[i+j] -= (unsigned short)t;
+            t >>= 16;
+         }
+         if (x[i+m] >= (unsigned short)t) goto putq;
+         /* perform correcting addition, because the current digit of
+            quotient is greater by one than its correct value */
+         q--;
+         t = 0;
+         for (j = 0; j < m; j++)
+         {  t += (unsigned int)x[i+j] + (unsigned int)y[j];
+            x[i+j] = (unsigned short)t;
+            t >>= 16;
+         }
+putq:    /* store the current digit of quotient */
+         x[i+m] = q;
+      }
+      /* divide divisor and remainder by the normalizing coefficient in
+         order to restore their original values */
+      if (d > 1)
+      {  t = 0;
+         for (i = m-1; i >= 0; i--)
+         {  t = (t << 16) + (unsigned int)x[i];
+            x[i] = (unsigned short)(t / (unsigned int)d);
+            t %= (unsigned int)d;
+         }
+         t = 0;
+         for (j = m-1; j >= 0; j--)
+         {  t = (t << 16) + (unsigned int)y[j];
+            y[j] = (unsigned short)(t / (unsigned int)d);
+            t %= (unsigned int)d;
+         }
+      }
+done: return;
+}
+
+/**********************************************************************/
+
+#if 0
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "glprng.h"
+
+#define N_MAX 7
+/* maximal number of digits in multiplicand */
+
+#define M_MAX 5
+/* maximal number of digits in multiplier */
+
+#define N_TEST 1000000
+/* number of tests */
+
+int main(void)
+{     RNG *rand;
+      int d, j, n, m, test;
+      unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX];
+      rand = rng_create_rand();
+      for (test = 1; test <= N_TEST; test++)
+      {  /* x[0,...,n-1] := multiplicand */
+         n = 1 + rng_unif_rand(rand, N_MAX-1);
+         assert(1 <= n && n <= N_MAX);
+         for (j = 0; j < n; j++)
+         {  d = rng_unif_rand(rand, 65536);
+            assert(0 <= d && d <= 65535);
+            x[j] = (unsigned short)d;
+         }
+         /* y[0,...,m-1] := multiplier */
+         m = 1 + rng_unif_rand(rand, M_MAX-1);
+         assert(1 <= m && m <= M_MAX);
+         for (j = 0; j < m; j++)
+         {  d = rng_unif_rand(rand, 65536);
+            assert(0 <= d && d <= 65535);
+            y[j] = (unsigned short)d;
+         }
+         if (y[m-1] == 0) y[m-1] = 1;
+         /* z[0,...,n+m-1] := x * y */
+         for (j = 0; j < n; j++) z[m+j] = x[j];
+         bigmul(n, m, z, y);
+         /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */
+         bigdiv(n, m, z, y);
+         /* z mod y must be 0 */
+         for (j = 0; j < m; j++) assert(z[j] == 0);
+         /* z div y must be x */
+         for (j = 0; j < n; j++) assert(z[m+j] == x[j]);
+      }
+      fprintf(stderr, "%d tests successfully passed\n", N_TEST);
+      rng_delete_rand(rand);
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glplib02.c
===================================================================
--- deps/glpk/src/glplib02.c	(revision 9)
+++ deps/glpk/src/glplib02.c	(revision 9)
@@ -0,0 +1,335 @@
+/* glplib02.c (64-bit arithmetic) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glplib.h"
+
+/***********************************************************************
+*  NAME
+*
+*  xlset - expand integer to long integer
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlset(int x);
+*
+*  RETURNS
+*
+*  The routine xlset returns x expanded to long integer. */
+
+glp_long xlset(int x)
+{     glp_long t;
+      t.lo = x, t.hi = (x >= 0 ? 0 : -1);
+      return t;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlneg - negate long integer
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlneg(glp_long x);
+*
+*  RETURNS
+*
+*  The routine xlneg returns the difference  0 - x. */
+
+glp_long xlneg(glp_long x)
+{     if (x.lo)
+         x.lo = - x.lo, x.hi = ~x.hi;
+      else
+         x.hi = - x.hi;
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xladd - add long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xladd(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xladd returns the sum x + y. */
+
+glp_long xladd(glp_long x, glp_long y)
+{     if ((unsigned int)x.lo <= 0xFFFFFFFF - (unsigned int)y.lo)
+         x.lo += y.lo, x.hi += y.hi;
+      else
+         x.lo += y.lo, x.hi += y.hi + 1;
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlsub - subtract long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlsub(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xlsub returns the difference x - y. */
+
+glp_long xlsub(glp_long x, glp_long y)
+{     return
+         xladd(x, xlneg(y));
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlcmp - compare long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int xlcmp(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xlcmp returns the sign of the difference x - y. */
+
+int xlcmp(glp_long x, glp_long y)
+{     if (x.hi >= 0 && y.hi <  0) return +1;
+      if (x.hi <  0 && y.hi >= 0) return -1;
+      if ((unsigned int)x.hi < (unsigned int)y.hi) return -1;
+      if ((unsigned int)x.hi > (unsigned int)y.hi) return +1;
+      if ((unsigned int)x.lo < (unsigned int)y.lo) return -1;
+      if ((unsigned int)x.lo > (unsigned int)y.lo) return +1;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xlmul - multiply long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_long xlmul(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xlmul returns the product x * y. */
+
+glp_long xlmul(glp_long x, glp_long y)
+{     unsigned short xx[8], yy[4];
+      xx[4] = (unsigned short)x.lo;
+      xx[5] = (unsigned short)(x.lo >> 16);
+      xx[6] = (unsigned short)x.hi;
+      xx[7] = (unsigned short)(x.hi >> 16);
+      yy[0] = (unsigned short)y.lo;
+      yy[1] = (unsigned short)(y.lo >> 16);
+      yy[2] = (unsigned short)y.hi;
+      yy[3] = (unsigned short)(y.hi >> 16);
+      bigmul(4, 4, xx, yy);
+      x.lo = (unsigned int)xx[0] | ((unsigned int)xx[1] << 16);
+      x.hi = (unsigned int)xx[2] | ((unsigned int)xx[3] << 16);
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xldiv - divide long integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  glp_ldiv xldiv(glp_long x, glp_long y);
+*
+*  RETURNS
+*
+*  The routine xldiv returns a structure of type glp_ldiv containing
+*  members quot (the quotient) and rem (the remainder), both of type
+*  glp_long. */
+
+glp_ldiv xldiv(glp_long x, glp_long y)
+{     glp_ldiv t;
+      int m, sx, sy;
+      unsigned short xx[8], yy[4];
+      /* sx := sign(x) */
+      sx = (x.hi < 0);
+      /* sy := sign(y) */
+      sy = (y.hi < 0);
+      /* x := |x| */
+      if (sx) x = xlneg(x);
+      /* y := |y| */
+      if (sy) y = xlneg(y);
+      /* compute x div y and x mod y */
+      xx[0] = (unsigned short)x.lo;
+      xx[1] = (unsigned short)(x.lo >> 16);
+      xx[2] = (unsigned short)x.hi;
+      xx[3] = (unsigned short)(x.hi >> 16);
+      yy[0] = (unsigned short)y.lo;
+      yy[1] = (unsigned short)(y.lo >> 16);
+      yy[2] = (unsigned short)y.hi;
+      yy[3] = (unsigned short)(y.hi >> 16);
+      if (yy[3])
+         m = 4;
+      else if (yy[2])
+         m = 3;
+      else if (yy[1])
+         m = 2;
+      else if (yy[0])
+         m = 1;
+      else
+         xerror("xldiv: divide by zero\n");
+      bigdiv(4 - m, m, xx, yy);
+      /* remainder in x[0], x[1], ..., x[m-1] */
+      t.rem.lo = (unsigned int)xx[0], t.rem.hi = 0;
+      if (m >= 2) t.rem.lo |= (unsigned int)xx[1] << 16;
+      if (m >= 3) t.rem.hi = (unsigned int)xx[2];
+      if (m >= 4) t.rem.hi |= (unsigned int)xx[3] << 16;
+      if (sx) t.rem = xlneg(t.rem);
+      /* quotient in x[m], x[m+1], ..., x[4] */
+      t.quot.lo = (unsigned int)xx[m], t.quot.hi = 0;
+      if (m <= 3) t.quot.lo |= (unsigned int)xx[m+1] << 16;
+      if (m <= 2) t.quot.hi = (unsigned int)xx[m+2];
+      if (m <= 1) t.quot.hi |= (unsigned int)xx[m+3] << 16;
+      if (sx ^ sy) t.quot = xlneg(t.quot);
+      return t;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  xltod - convert long integer to double
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  double xltod(glp_long x);
+*
+*  RETURNS
+*
+*  The routine xltod returns x converted to double. */
+
+double xltod(glp_long x)
+{     double s, z;
+      if (x.hi >= 0)
+         s = +1.0;
+      else
+         s = -1.0, x = xlneg(x);
+      if (x.hi >= 0)
+         z = 4294967296.0 * (double)x.hi + (double)(unsigned int)x.lo;
+      else
+      {  xassert(x.hi == 0x80000000 && x.lo == 0x00000000);
+         z = 9223372036854775808.0; /* 2^63 */
+      }
+      return s * z;
+}
+
+char *xltoa(glp_long x, char *s)
+{     /* convert long integer to character string */
+      static const char *d = "0123456789";
+      glp_ldiv t;
+      int neg, len;
+      if (x.hi >= 0)
+         neg = 0;
+      else
+         neg = 1, x = xlneg(x);
+      if (x.hi >= 0)
+      {  len = 0;
+         while (!(x.hi == 0 && x.lo == 0))
+         {  t = xldiv(x, xlset(10));
+            xassert(0 <= t.rem.lo && t.rem.lo <= 9);
+            s[len++] = d[t.rem.lo];
+            x = t.quot;
+         }
+         if (len == 0) s[len++] = d[0];
+         if (neg) s[len++] = '-';
+         s[len] = '\0';
+         strrev(s);
+      }
+      else
+         strcpy(s, "-9223372036854775808"); /* -2^63 */
+      return s;
+}
+
+/**********************************************************************/
+
+#if 0
+#include "glprng.h"
+
+#define N_TEST 1000000
+/* number of tests */
+
+static glp_long myrand(RNG *rand)
+{     glp_long x;
+      int k;
+      k = rng_unif_rand(rand, 4);
+      xassert(0 <= k && k <= 3);
+      x.lo = rng_unif_rand(rand, 65536);
+      if (k == 1 || k == 3)
+      {  x.lo <<= 16;
+         x.lo += rng_unif_rand(rand, 65536);
+      }
+      if (k <= 1)
+         x.hi = 0;
+      else
+         x.hi = rng_unif_rand(rand, 65536);
+      if (k == 3)
+      {  x.hi <<= 16;
+         x.hi += rng_unif_rand(rand, 65536);
+      }
+      if (rng_unif_rand(rand, 2)) x = xlneg(x);
+      return x;
+}
+
+int main(void)
+{     RNG *rand;
+      glp_long x, y;
+      glp_ldiv z;
+      int test;
+      rand = rng_create_rand();
+      for (test = 1; test <= N_TEST; test++)
+      {  x = myrand(rand);
+         y = myrand(rand);
+         if (y.lo == 0 && y.hi == 0) y.lo = 1;
+         /* z.quot := x div y, z.rem := x mod y */
+         z = xldiv(x, y);
+         /* x must be equal to y * z.quot + z.rem */
+         xassert(xlcmp(x, xladd(xlmul(y, z.quot), z.rem)) == 0);
+      }
+      xprintf("%d tests successfully passed\n", N_TEST);
+      rng_delete_rand(rand);
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glplib03.c
===================================================================
--- deps/glpk/src/glplib03.c	(revision 9)
+++ deps/glpk/src/glplib03.c	(revision 9)
@@ -0,0 +1,692 @@
+/* glplib03.c (miscellaneous library routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glplib.h"
+
+/***********************************************************************
+*  NAME
+*
+*  str2int - convert character string to value of int type
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int str2int(const char *str, int *val);
+*
+*  DESCRIPTION
+*
+*  The routine str2int converts the character string str to a value of
+*  integer type and stores the value into location, which the parameter
+*  val points to (in the case of error content of this location is not
+*  changed).
+*
+*  RETURNS
+*
+*  The routine returns one of the following error codes:
+*
+*  0 - no error;
+*  1 - value out of range;
+*  2 - character string is syntactically incorrect. */
+
+int str2int(const char *str, int *_val)
+{     int d, k, s, val = 0;
+      /* scan optional sign */
+      if (str[0] == '+')
+         s = +1, k = 1;
+      else if (str[0] == '-')
+         s = -1, k = 1;
+      else
+         s = +1, k = 0;
+      /* check for the first digit */
+      if (!isdigit((unsigned char)str[k])) return 2;
+      /* scan digits */
+      while (isdigit((unsigned char)str[k]))
+      {  d = str[k++] - '0';
+         if (s > 0)
+         {  if (val > INT_MAX / 10) return 1;
+            val *= 10;
+            if (val > INT_MAX - d) return 1;
+            val += d;
+         }
+         else
+         {  if (val < INT_MIN / 10) return 1;
+            val *= 10;
+            if (val < INT_MIN + d) return 1;
+            val -= d;
+         }
+      }
+      /* check for terminator */
+      if (str[k] != '\0') return 2;
+      /* conversion has been done */
+      *_val = val;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  str2num - convert character string to value of double type
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int str2num(const char *str, double *val);
+*
+*  DESCRIPTION
+*
+*  The routine str2num converts the character string str to a value of
+*  double type and stores the value into location, which the parameter
+*  val points to (in the case of error content of this location is not
+*  changed).
+*
+*  RETURNS
+*
+*  The routine returns one of the following error codes:
+*
+*  0 - no error;
+*  1 - value out of range;
+*  2 - character string is syntactically incorrect. */
+
+int str2num(const char *str, double *_val)
+{     int k;
+      double val;
+      /* scan optional sign */
+      k = (str[0] == '+' || str[0] == '-' ? 1 : 0);
+      /* check for decimal point */
+      if (str[k] == '.')
+      {  k++;
+         /* a digit should follow it */
+         if (!isdigit((unsigned char)str[k])) return 2;
+         k++;
+         goto frac;
+      }
+      /* integer part should start with a digit */
+      if (!isdigit((unsigned char)str[k])) return 2;
+      /* scan integer part */
+      while (isdigit((unsigned char)str[k])) k++;
+      /* check for decimal point */
+      if (str[k] == '.') k++;
+frac: /* scan optional fraction part */
+      while (isdigit((unsigned char)str[k])) k++;
+      /* check for decimal exponent */
+      if (str[k] == 'E' || str[k] == 'e')
+      {  k++;
+         /* scan optional sign */
+         if (str[k] == '+' || str[k] == '-') k++;
+         /* a digit should follow E, E+ or E- */
+         if (!isdigit((unsigned char)str[k])) return 2;
+      }
+      /* scan optional exponent part */
+      while (isdigit((unsigned char)str[k])) k++;
+      /* check for terminator */
+      if (str[k] != '\0') return 2;
+      /* perform conversion */
+      {  char *endptr;
+         val = strtod(str, &endptr);
+         if (*endptr != '\0') return 2;
+      }
+      /* check for overflow */
+      if (!(-DBL_MAX <= val && val <= +DBL_MAX)) return 1;
+      /* check for underflow */
+      if (-DBL_MIN < val && val < +DBL_MIN) val = 0.0;
+      /* conversion has been done */
+      *_val = val;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  strspx - remove all spaces from character string
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  char *strspx(char *str);
+*
+*  DESCRIPTION
+*
+*  The routine strspx removes all spaces from the character string str.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the character string.
+*
+*  EXAMPLES
+*
+*  strspx("   Errare   humanum   est   ") => "Errarehumanumest"
+*
+*  strspx("      ")                       => "" */
+
+char *strspx(char *str)
+{     char *s, *t;
+      for (s = t = str; *s; s++) if (*s != ' ') *t++ = *s;
+      *t = '\0';
+      return str;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  strtrim - remove trailing spaces from character string
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  char *strtrim(char *str);
+*
+*  DESCRIPTION
+*
+*  The routine strtrim removes trailing spaces from the character
+*  string str.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the character string.
+*
+*  EXAMPLES
+*
+*  strtrim("Errare humanum est   ") => "Errare humanum est"
+*
+*  strtrim("      ")                => "" */
+
+char *strtrim(char *str)
+{     char *t;
+      for (t = strrchr(str, '\0') - 1; t >= str; t--)
+      {  if (*t != ' ') break;
+         *t = '\0';
+      }
+      return str;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  strrev - reverse character string
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  char *strrev(char *s);
+*
+*  DESCRIPTION
+*
+*  The routine strrev changes characters in a character string s to the
+*  reverse order, except the terminating null character.
+*
+*  RETURNS
+*
+*  The routine returns the pointer s.
+*
+*  EXAMPLES
+*
+*  strrev("")                => ""
+*
+*  strrev("Today is Monday") => "yadnoM si yadoT" */
+
+char *strrev(char *s)
+{     int i, j;
+      char t;
+      for (i = 0, j = strlen(s)-1; i < j; i++, j--)
+         t = s[i], s[i] = s[j], s[j] = t;
+      return s;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  gcd - find greatest common divisor of two integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int gcd(int x, int y);
+*
+*  RETURNS
+*
+*  The routine gcd returns gcd(x, y), the greatest common divisor of
+*  the two positive integers given.
+*
+*  ALGORITHM
+*
+*  The routine gcd is based on Euclid's algorithm.
+*
+*  REFERENCES
+*
+*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
+*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
+*  Greatest Common Divisor, pp. 333-56. */
+
+int gcd(int x, int y)
+{     int r;
+      xassert(x > 0 && y > 0);
+      while (y > 0)
+         r = x % y, x = y, y = r;
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  gcdn - find greatest common divisor of n integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int gcdn(int n, int x[]);
+*
+*  RETURNS
+*
+*  The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest
+*  common divisor of n positive integers given, n > 0.
+*
+*  BACKGROUND
+*
+*  The routine gcdn is based on the following identity:
+*
+*     gcd(x, y, z) = gcd(gcd(x, y), z).
+*
+*  REFERENCES
+*
+*  Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical
+*  Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The
+*  Greatest Common Divisor, pp. 333-56. */
+
+int gcdn(int n, int x[])
+{     int d, j;
+      xassert(n > 0);
+      for (j = 1; j <= n; j++)
+      {  xassert(x[j] > 0);
+         if (j == 1)
+            d = x[1];
+         else
+            d = gcd(d, x[j]);
+         if (d == 1) break;
+      }
+      return d;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lcm - find least common multiple of two integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int lcm(int x, int y);
+*
+*  RETURNS
+*
+*  The routine lcm returns lcm(x, y), the least common multiple of the
+*  two positive integers given. In case of integer overflow the routine
+*  returns zero.
+*
+*  BACKGROUND
+*
+*  The routine lcm is based on the following identity:
+*
+*     lcm(x, y) = (x * y) / gcd(x, y) = x * [y / gcd(x, y)],
+*
+*  where gcd(x, y) is the greatest common divisor of x and y. */
+
+int lcm(int x, int y)
+{     xassert(x > 0);
+      xassert(y > 0);
+      y /= gcd(x, y);
+      if (x > INT_MAX / y) return 0;
+      return x * y;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lcmn - find least common multiple of n integers
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int lcmn(int n, int x[]);
+*
+*  RETURNS
+*
+*  The routine lcmn returns lcm(x[1], x[2], ..., x[n]), the least
+*  common multiple of n positive integers given, n > 0. In case of
+*  integer overflow the routine returns zero.
+*
+*  BACKGROUND
+*
+*  The routine lcmn is based on the following identity:
+*
+*     lcmn(x, y, z) = lcm(lcm(x, y), z),
+*
+*  where lcm(x, y) is the least common multiple of x and y. */
+
+int lcmn(int n, int x[])
+{     int m, j;
+      xassert(n > 0);
+      for (j = 1; j <= n; j++)
+      {  xassert(x[j] > 0);
+         if (j == 1)
+            m = x[1];
+         else
+            m = lcm(m, x[j]);
+         if (m == 0) break;
+      }
+      return m;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  round2n - round floating-point number to nearest power of two
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  double round2n(double x);
+*
+*  RETURNS
+*
+*  Given a positive floating-point value x the routine round2n returns
+*  2^n such that |x - 2^n| is minimal.
+*
+*  EXAMPLES
+*
+*  round2n(10.1) = 2^3 = 8
+*  round2n(15.3) = 2^4 = 16
+*  round2n(0.01) = 2^(-7) = 0.0078125
+*
+*  BACKGROUND
+*
+*  Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part,
+*  e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so
+*  if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e
+*  otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e
+*  or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */
+
+double round2n(double x)
+{     int e;
+      double f;
+      xassert(x > 0.0);
+      f = frexp(x, &e);
+      return ldexp(1.0, f <= 0.75 ? e-1 : e);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  fp2rat - convert floating-point number to rational number
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int fp2rat(double x, double eps, double *p, double *q);
+*
+*  DESCRIPTION
+*
+*  Given a floating-point number 0 <= x < 1 the routine fp2rat finds
+*  its "best" rational approximation p / q, where p >= 0 and q > 0 are
+*  integer numbers, such that |x - p / q| <= eps.
+*
+*  RETURNS
+*
+*  The routine fp2rat returns the number of iterations used to achieve
+*  the specified precision eps.
+*
+*  EXAMPLES
+*
+*  For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine
+*  gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543.
+*
+*  BACKGROUND
+*
+*  It is well known that every positive real number x can be expressed
+*  as the following continued fraction:
+*
+*     x = b[0] + a[1]
+*                ------------------------
+*                b[1] + a[2]
+*                       -----------------
+*                       b[2] + a[3]
+*                              ----------
+*                              b[3] + ...
+*
+*  where:
+*
+*     a[k] = 1,                  k = 0, 1, 2, ...
+*
+*     b[k] = floor(x[k]),        k = 0, 1, 2, ...
+*
+*     x[0] = x,
+*
+*     x[k] = 1 / frac(x[k-1]),   k = 1, 2, 3, ...
+*
+*  To find the "best" rational approximation of x the routine computes
+*  partial fractions f[k] by dropping after k terms as follows:
+*
+*     f[k] = A[k] / B[k],
+*
+*  where:
+*
+*     A[-1] = 1,   A[0] = b[0],   B[-1] = 0,   B[0] = 1,
+*
+*     A[k] = b[k] * A[k-1] + a[k] * A[k-2],
+*
+*     B[k] = b[k] * B[k-1] + a[k] * B[k-2].
+*
+*  Once the condition
+*
+*     |x - f[k]| <= eps
+*
+*  has been satisfied, the routine reports p = A[k] and q = B[k] as the
+*  final answer.
+*
+*  In the table below here is some statistics obtained for one million
+*  random numbers uniformly distributed in the range [0, 1).
+*
+*      eps      max p   mean p      max q    mean q  max k   mean k
+*     -------------------------------------------------------------
+*     1e-1          8      1.6          9       3.2    3      1.4
+*     1e-2         98      6.2         99      12.4    5      2.4
+*     1e-3        997     20.7        998      41.5    8      3.4
+*     1e-4       9959     66.6       9960     133.5   10      4.4
+*     1e-5      97403    211.7      97404     424.2   13      5.3
+*     1e-6     479669    669.9     479670    1342.9   15      6.3
+*     1e-7    1579030   2127.3    3962146    4257.8   16      7.3
+*     1e-8   26188823   6749.4   26188824   13503.4   19      8.2
+*
+*  REFERENCES
+*
+*  W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory
+*  and Applications," Encyclopedia on Mathematics and Its Applications,
+*  Addison-Wesley, 1980. */
+
+int fp2rat(double x, double eps, double *p, double *q)
+{     int k;
+      double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp;
+      if (!(0.0 <= x && x < 1.0))
+         xerror("fp2rat: x = %g; number out of range\n", x);
+      for (k = 0; ; k++)
+      {  xassert(k <= 100);
+         if (k == 0)
+         {  /* x[0] = x */
+            xk = x;
+            /* A[-1] = 1 */
+            Akm1 = 1.0;
+            /* A[0] = b[0] = floor(x[0]) = 0 */
+            Ak = 0.0;
+            /* B[-1] = 0 */
+            Bkm1 = 0.0;
+            /* B[0] = 1 */
+            Bk = 1.0;
+         }
+         else
+         {  /* x[k] = 1 / frac(x[k-1]) */
+            temp = xk - floor(xk);
+            xassert(temp != 0.0);
+            xk = 1.0 / temp;
+            /* a[k] = 1 */
+            ak = 1.0;
+            /* b[k] = floor(x[k]) */
+            bk = floor(xk);
+            /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */
+            temp = bk * Ak + ak * Akm1;
+            Akm1 = Ak, Ak = temp;
+            /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */
+            temp = bk * Bk + ak * Bkm1;
+            Bkm1 = Bk, Bk = temp;
+         }
+         /* f[k] = A[k] / B[k] */
+         fk = Ak / Bk;
+#if 0
+         print("%.*g / %.*g = %.*g", DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG,
+            fk);
+#endif
+         if (fabs(x - fk) <= eps) break;
+      }
+      *p = Ak;
+      *q = Bk;
+      return k;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  jday - convert calendar date to Julian day number
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  int jday(int d, int m, int y);
+*
+*  DESCRIPTION
+*
+*  The routine jday converts a calendar date, Gregorian calendar, to
+*  corresponding Julian day number j.
+*
+*  From the given day d, month m, and year y, the Julian day number j
+*  is computed without using tables.
+*
+*  The routine is valid for 1 <= y <= 4000.
+*
+*  RETURNS
+*
+*  The routine jday returns the Julian day number, or negative value if
+*  the specified date is incorrect.
+*
+*  REFERENCES
+*
+*  R. G. Tantzen, Algorithm 199: conversions between calendar date and
+*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
+*  Aug. 1963. */
+
+int jday(int d, int m, int y)
+{     int c, ya, j, dd;
+      if (!(1 <= d && d <= 31 && 1 <= m && m <= 12 && 1 <= y &&
+            y <= 4000))
+      {  j = -1;
+         goto done;
+      }
+      if (m >= 3) m -= 3; else m += 9, y--;
+      c = y / 100;
+      ya = y - 100 * c;
+      j = (146097 * c) / 4 + (1461 * ya) / 4 + (153 * m + 2) / 5 + d +
+         1721119;
+      jdate(j, &dd, NULL, NULL);
+      if (d != dd) j = -1;
+done: return j;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  jdate - convert Julian day number to calendar date
+*
+*  SYNOPSIS
+*
+*  #include "glplib.h"
+*  void jdate(int j, int *d, int *m, int *y);
+*
+*  DESCRIPTION
+*
+*  The routine jdate converts a Julian day number j to corresponding
+*  calendar date, Gregorian calendar.
+*
+*  The day d, month m, and year y are computed without using tables and
+*  stored in corresponding locations.
+*
+*  The routine is valid for 1721426 <= j <= 3182395.
+*
+*  RETURNS
+*
+*  If the conversion is successful, the routine returns zero, otherwise
+*  non-zero.
+*
+*  REFERENCES
+*
+*  R. G. Tantzen, Algorithm 199: conversions between calendar date and
+*  Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444,
+*  Aug. 1963. */
+
+int jdate(int j, int *_d, int *_m, int *_y)
+{     int d, m, y, ret = 0;
+      if (!(1721426 <= j && j <= 3182395))
+      {  ret = 1;
+         goto done;
+      }
+      j -= 1721119;
+      y = (4 * j - 1) / 146097;
+      j = (4 * j - 1) % 146097;
+      d = j / 4;
+      j = (4 * d + 3) / 1461;
+      d = (4 * d + 3) % 1461;
+      d = (d + 4) / 4;
+      m = (5 * d - 3) / 153;
+      d = (5 * d - 3) % 153;
+      d = (d + 5) / 5;
+      y = 100 * y + j;
+      if (m <= 9) m += 3; else m -= 9, y++;
+      if (_d != NULL) *_d = d;
+      if (_m != NULL) *_m = m;
+      if (_y != NULL) *_y = y;
+done: return ret;
+}
+
+#if 0
+int main(void)
+{     int jbeg, jend, j, d, m, y;
+      jbeg = jday(1, 1, 1);
+      jend = jday(31, 12, 4000);
+      for (j = jbeg; j <= jend; j++)
+      {  xassert(jdate(j, &d, &m, &y) == 0);
+         xassert(jday(d, m, y) == j);
+      }
+      xprintf("Routines jday and jdate work correctly.\n");
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glplpf.c
===================================================================
--- deps/glpk/src/glplpf.c	(revision 9)
+++ deps/glpk/src/glplpf.c	(revision 9)
@@ -0,0 +1,978 @@
+/* glplpf.c (LP basis factorization, Schur complement version) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glplpf.h"
+#include "glpenv.h"
+#define xfault xerror
+
+#define _GLPLPF_DEBUG 0
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define M_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the basis matrix */
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_create_it - create LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  LPF *lpf_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_create_it creates a program object, which represents
+*  a factorization of LP basis.
+*
+*  RETURNS
+*
+*  The routine lpf_create_it returns a pointer to the object created. */
+
+LPF *lpf_create_it(void)
+{     LPF *lpf;
+#if _GLPLPF_DEBUG
+      xprintf("lpf_create_it: warning: debug mode enabled\n");
+#endif
+      lpf = xmalloc(sizeof(LPF));
+      lpf->valid = 0;
+      lpf->m0_max = lpf->m0 = 0;
+      lpf->luf = luf_create_it();
+      lpf->m = 0;
+      lpf->B = NULL;
+      lpf->n_max = 50;
+      lpf->n = 0;
+      lpf->R_ptr = lpf->R_len = NULL;
+      lpf->S_ptr = lpf->S_len = NULL;
+      lpf->scf = NULL;
+      lpf->P_row = lpf->P_col = NULL;
+      lpf->Q_row = lpf->Q_col = NULL;
+      lpf->v_size = 1000;
+      lpf->v_ptr = 0;
+      lpf->v_ind = NULL;
+      lpf->v_val = NULL;
+      lpf->work1 = lpf->work2 = NULL;
+      return lpf;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_factorize - compute LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
+*     (void *info, int j, int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_factorize computes the factorization of the basis
+*  matrix B specified by the routine col.
+*
+*  The parameter lpf specified the basis factorization data structure
+*  created with the routine lpf_create_it.
+*
+*  The parameter m specifies the order of B, m > 0.
+*
+*  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
+*  number of j-th column of B in some original matrix. The array bh is
+*  optional and can be specified as NULL.
+*
+*  The formal routine col specifies the matrix B to be factorized. To
+*  obtain j-th column of A the routine lpf_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully computed.
+*
+*  LPF_ESING
+*     The specified matrix is singular within the working precision.
+*
+*  LPF_ECOND
+*     The specified matrix is ill-conditioned.
+*
+*  For more details see comments to the routine luf_factorize. */
+
+int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info)
+{     int k, ret;
+#if _GLPLPF_DEBUG
+      int i, j, len, *ind;
+      double *B, *val;
+#endif
+      xassert(bh == bh);
+      if (m < 1)
+         xfault("lpf_factorize: m = %d; invalid parameter\n", m);
+      if (m > M_MAX)
+         xfault("lpf_factorize: m = %d; matrix too big\n", m);
+      lpf->m0 = lpf->m = m;
+      /* invalidate the factorization */
+      lpf->valid = 0;
+      /* allocate/reallocate arrays, if necessary */
+      if (lpf->R_ptr == NULL)
+         lpf->R_ptr = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->R_len == NULL)
+         lpf->R_len = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->S_ptr == NULL)
+         lpf->S_ptr = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->S_len == NULL)
+         lpf->S_len = xcalloc(1+lpf->n_max, sizeof(int));
+      if (lpf->scf == NULL)
+         lpf->scf = scf_create_it(lpf->n_max);
+      if (lpf->v_ind == NULL)
+         lpf->v_ind = xcalloc(1+lpf->v_size, sizeof(int));
+      if (lpf->v_val == NULL)
+         lpf->v_val = xcalloc(1+lpf->v_size, sizeof(double));
+      if (lpf->m0_max < m)
+      {  if (lpf->P_row != NULL) xfree(lpf->P_row);
+         if (lpf->P_col != NULL) xfree(lpf->P_col);
+         if (lpf->Q_row != NULL) xfree(lpf->Q_row);
+         if (lpf->Q_col != NULL) xfree(lpf->Q_col);
+         if (lpf->work1 != NULL) xfree(lpf->work1);
+         if (lpf->work2 != NULL) xfree(lpf->work2);
+         lpf->m0_max = m + 100;
+         lpf->P_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->P_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->Q_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->Q_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
+         lpf->work1 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
+         lpf->work2 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
+      }
+      /* try to factorize the basis matrix */
+      switch (luf_factorize(lpf->luf, m, col, info))
+      {  case 0:
+            break;
+         case LUF_ESING:
+            ret = LPF_ESING;
+            goto done;
+         case LUF_ECOND:
+            ret = LPF_ECOND;
+            goto done;
+         default:
+            xassert(lpf != lpf);
+      }
+      /* the basis matrix has been successfully factorized */
+      lpf->valid = 1;
+#if _GLPLPF_DEBUG
+      /* store the basis matrix for debugging */
+      if (lpf->B != NULL) xfree(lpf->B);
+      xassert(m <= 32767);
+      lpf->B = B = xcalloc(1+m*m, sizeof(double));
+      ind = xcalloc(1+m, sizeof(int));
+      val = xcalloc(1+m, sizeof(double));
+      for (k = 1; k <= m * m; k++)
+         B[k] = 0.0;
+      for (j = 1; j <= m; j++)
+      {  len = col(info, j, ind, val);
+         xassert(0 <= len && len <= m);
+         for (k = 1; k <= len; k++)
+         {  i = ind[k];
+            xassert(1 <= i && i <= m);
+            xassert(B[(i - 1) * m + j] == 0.0);
+            xassert(val[k] != 0.0);
+            B[(i - 1) * m + j] = val[k];
+         }
+      }
+      xfree(ind);
+      xfree(val);
+#endif
+      /* B = B0, so there are no additional rows/columns */
+      lpf->n = 0;
+      /* reset the Schur complement factorization */
+      scf_reset_it(lpf->scf);
+      /* P := Q := I */
+      for (k = 1; k <= m; k++)
+      {  lpf->P_row[k] = lpf->P_col[k] = k;
+         lpf->Q_row[k] = lpf->Q_col[k] = k;
+      }
+      /* make all SVA locations free */
+      lpf->v_ptr = 1;
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  The routine r_prod computes the product y := y + alpha * R * x,
+*  where x is a n-vector, alpha is a scalar, y is a m0-vector.
+*
+*  Since matrix R is available by columns, the product is computed as
+*  a linear combination:
+*
+*     y := y + alpha * (R[1] * x[1] + ... + R[n] * x[n]),
+*
+*  where R[j] is j-th column of R. */
+
+static void r_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *R_ptr = lpf->R_ptr;
+      int *R_len = lpf->R_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int j, beg, end, ptr;
+      double t;
+      for (j = 1; j <= n; j++)
+      {  if (x[j] == 0.0) continue;
+         /* y := y + alpha * R[j] * x[j] */
+         t = a * x[j];
+         beg = R_ptr[j];
+         end = beg + R_len[j];
+         for (ptr = beg; ptr < end; ptr++)
+            y[v_ind[ptr]] += t * v_val[ptr];
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine rt_prod computes the product y := y + alpha * R' * x,
+*  where R' is a matrix transposed to R, x is a m0-vector, alpha is a
+*  scalar, y is a n-vector.
+*
+*  Since matrix R is available by columns, the product components are
+*  computed as inner products:
+*
+*     y[j] := y[j] + alpha * (j-th column of R) * x
+*
+*  for j = 1, 2, ..., n. */
+
+static void rt_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *R_ptr = lpf->R_ptr;
+      int *R_len = lpf->R_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int j, beg, end, ptr;
+      double t;
+      for (j = 1; j <= n; j++)
+      {  /* t := (j-th column of R) * x */
+         t = 0.0;
+         beg = R_ptr[j];
+         end = beg + R_len[j];
+         for (ptr = beg; ptr < end; ptr++)
+            t += v_val[ptr] * x[v_ind[ptr]];
+         /* y[j] := y[j] + alpha * t */
+         y[j] += a * t;
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine s_prod computes the product y := y + alpha * S * x,
+*  where x is a m0-vector, alpha is a scalar, y is a n-vector.
+*
+*  Since matrix S is available by rows, the product components are
+*  computed as inner products:
+*
+*     y[i] = y[i] + alpha * (i-th row of S) * x
+*
+*  for i = 1, 2, ..., n. */
+
+static void s_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *S_ptr = lpf->S_ptr;
+      int *S_len = lpf->S_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int i, beg, end, ptr;
+      double t;
+      for (i = 1; i <= n; i++)
+      {  /* t := (i-th row of S) * x */
+         t = 0.0;
+         beg = S_ptr[i];
+         end = beg + S_len[i];
+         for (ptr = beg; ptr < end; ptr++)
+            t += v_val[ptr] * x[v_ind[ptr]];
+         /* y[i] := y[i] + alpha * t */
+         y[i] += a * t;
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine st_prod computes the product y := y + alpha * S' * x,
+*  where S' is a matrix transposed to S, x is a n-vector, alpha is a
+*  scalar, y is m0-vector.
+*
+*  Since matrix R is available by rows, the product is computed as a
+*  linear combination:
+*
+*     y := y + alpha * (S'[1] * x[1] + ... + S'[n] * x[n]),
+*
+*  where S'[i] is i-th row of S. */
+
+static void st_prod(LPF *lpf, double y[], double a, const double x[])
+{     int n = lpf->n;
+      int *S_ptr = lpf->S_ptr;
+      int *S_len = lpf->S_len;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      int i, beg, end, ptr;
+      double t;
+      for (i = 1; i <= n; i++)
+      {  if (x[i] == 0.0) continue;
+         /* y := y + alpha * S'[i] * x[i] */
+         t = a * x[i];
+         beg = S_ptr[i];
+         end = beg + S_len[i];
+         for (ptr = beg; ptr < end; ptr++)
+            y[v_ind[ptr]] += t * v_val[ptr];
+      }
+      return;
+}
+
+#if _GLPLPF_DEBUG
+/***********************************************************************
+*  The routine check_error computes the maximal relative error between
+*  left- and right-hand sides for the system B * x = b (if tr is zero)
+*  or B' * x = b (if tr is non-zero), where B' is a matrix transposed
+*  to B. (This routine is intended for debugging only.) */
+
+static void check_error(LPF *lpf, int tr, const double x[],
+      const double b[])
+{     int m = lpf->m;
+      double *B = lpf->B;
+      int i, j;
+      double  d, dmax = 0.0, s, t, tmax;
+      for (i = 1; i <= m; i++)
+      {  s = 0.0;
+         tmax = 1.0;
+         for (j = 1; j <= m; j++)
+         {  if (!tr)
+               t = B[m * (i - 1) + j] * x[j];
+            else
+               t = B[m * (j - 1) + i] * x[j];
+            if (tmax < fabs(t)) tmax = fabs(t);
+            s += t;
+         }
+         d = fabs(s - b[i]) / tmax;
+         if (dmax < d) dmax = d;
+      }
+      if (dmax > 1e-8)
+         xprintf("%s: dmax = %g; relative error too large\n",
+            !tr ? "lpf_ftran" : "lpf_btran", dmax);
+      return;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_ftran - perform forward transformation (solve system B*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  void lpf_ftran(LPF *lpf, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_ftran performs forward transformation, i.e. solves
+*  the system B*x = b, where B is the basis matrix, x is the vector of
+*  unknowns to be computed, b is the vector of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  BACKGROUND
+*
+*  Solution of the system B * x = b can be obtained by solving the
+*  following augmented system:
+*
+*     ( B  F^) ( x )   ( b )
+*     (      ) (   ) = (   )
+*     ( G^ H^) ( y )   ( 0 )
+*
+*  which, using the main equality, can be written as follows:
+*
+*       ( L0 0 ) ( U0 R )   ( x )   ( b )
+*     P (      ) (      ) Q (   ) = (   )
+*       ( S  I ) ( 0  C )   ( y )   ( 0 )
+*
+*  therefore,
+*
+*     ( x )      ( U0 R )-1 ( L0 0 )-1    ( b )
+*     (   ) = Q' (      )   (      )   P' (   )
+*     ( y )      ( 0  C )   ( S  I )      ( 0 )
+*
+*  Thus, computing the solution includes the following steps:
+*
+*  1. Compute
+*
+*     ( f )      ( b )
+*     (   ) = P' (   )
+*     ( g )      ( 0 )
+*
+*  2. Solve the system
+*
+*     ( f1 )   ( L0 0 )-1 ( f )      ( L0 0 ) ( f1 )   ( f )
+*     (    ) = (      )   (   )  =>  (      ) (    ) = (   )
+*     ( g1 )   ( S  I )   ( g )      ( S  I ) ( g1 )   ( g )
+*
+*     from which it follows that:
+*
+*     { L0 * f1      = f      f1 = inv(L0) * f
+*     {                   =>
+*     {  S * f1 + g1 = g      g1 = g - S * f1
+*
+*  3. Solve the system
+*
+*     ( f2 )   ( U0 R )-1 ( f1 )      ( U0 R ) ( f2 )   ( f1 )
+*     (    ) = (      )   (    )  =>  (      ) (    ) = (    )
+*     ( g2 )   ( 0  C )   ( g1 )      ( 0  C ) ( g2 )   ( g1 )
+*
+*     from which it follows that:
+*
+*     { U0 * f2 + R * g2 = f1      f2 = inv(U0) * (f1 - R * g2)
+*     {                        =>
+*     {           C * g2 = g1      g2 = inv(C) * g1
+*
+*  4. Compute
+*
+*     ( x )      ( f2 )
+*     (   ) = Q' (    )
+*     ( y )      ( g2 )                                               */
+
+void lpf_ftran(LPF *lpf, double x[])
+{     int m0 = lpf->m0;
+      int m = lpf->m;
+      int n  = lpf->n;
+      int *P_col = lpf->P_col;
+      int *Q_col = lpf->Q_col;
+      double *fg = lpf->work1;
+      double *f = fg;
+      double *g = fg + m0;
+      int i, ii;
+#if _GLPLPF_DEBUG
+      double *b;
+#endif
+      if (!lpf->valid)
+         xfault("lpf_ftran: the factorization is not valid\n");
+      xassert(0 <= m && m <= m0 + n);
+#if _GLPLPF_DEBUG
+      /* save the right-hand side vector */
+      b = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) b[i] = x[i];
+#endif
+      /* (f g) := inv(P) * (b 0) */
+      for (i = 1; i <= m0 + n; i++)
+         fg[i] = ((ii = P_col[i]) <= m ? x[ii] : 0.0);
+      /* f1 := inv(L0) * f */
+      luf_f_solve(lpf->luf, 0, f);
+      /* g1 := g - S * f1 */
+      s_prod(lpf, g, -1.0, f);
+      /* g2 := inv(C) * g1 */
+      scf_solve_it(lpf->scf, 0, g);
+      /* f2 := inv(U0) * (f1 - R * g2) */
+      r_prod(lpf, f, -1.0, g);
+      luf_v_solve(lpf->luf, 0, f);
+      /* (x y) := inv(Q) * (f2 g2) */
+      for (i = 1; i <= m; i++)
+         x[i] = fg[Q_col[i]];
+#if _GLPLPF_DEBUG
+      /* check relative error in solution */
+      check_error(lpf, 0, x, b);
+      xfree(b);
+#endif
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_btran - perform backward transformation (solve system B'*x = b)
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  void lpf_btran(LPF *lpf, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_btran performs backward transformation, i.e. solves
+*  the system B'*x = b, where B' is a matrix transposed to the basis
+*  matrix B, x is the vector of unknowns to be computed, b is the vector
+*  of right-hand sides.
+*
+*  On entry elements of the vector b should be stored in dense format
+*  in locations x[1], ..., x[m], where m is the number of rows. On exit
+*  the routine stores elements of the vector x in the same locations.
+*
+*  BACKGROUND
+*
+*  Solution of the system B' * x = b, where B' is a matrix transposed
+*  to B, can be obtained by solving the following augmented system:
+*
+*     ( B  F^)T ( x )   ( b )
+*     (      )  (   ) = (   )
+*     ( G^ H^)  ( y )   ( 0 )
+*
+*  which, using the main equality, can be written as follows:
+*
+*      T ( U0 R )T ( L0 0 )T  T ( x )   ( b )
+*     Q  (      )  (      )  P  (   ) = (   )
+*        ( 0  C )  ( S  I )     ( y )   ( 0 )
+*
+*  or, equivalently, as follows:
+*
+*        ( U'0 0 ) ( L'0 S')    ( x )   ( b )
+*     Q' (       ) (       ) P' (   ) = (   )
+*        ( R'  C') ( 0   I )    ( y )   ( 0 )
+*
+*  therefore,
+*
+*     ( x )     ( L'0 S')-1 ( U'0 0 )-1   ( b )
+*     (   ) = P (       )   (       )   Q (   )
+*     ( y )     ( 0   I )   ( R'  C')     ( 0 )
+*
+*  Thus, computing the solution includes the following steps:
+*
+*  1. Compute
+*
+*     ( f )     ( b )
+*     (   ) = Q (   )
+*     ( g )     ( 0 )
+*
+*  2. Solve the system
+*
+*     ( f1 )   ( U'0 0 )-1 ( f )      ( U'0 0 ) ( f1 )   ( f )
+*     (    ) = (       )   (   )  =>  (       ) (    ) = (   )
+*     ( g1 )   ( R'  C')   ( g )      ( R'  C') ( g1 )   ( g )
+*
+*     from which it follows that:
+*
+*     { U'0 * f1           = f      f1 = inv(U'0) * f
+*     {                         =>
+*     { R'  * f1 + C' * g1 = g      g1 = inv(C') * (g - R' * f1)
+*
+*  3. Solve the system
+*
+*     ( f2 )   ( L'0 S')-1 ( f1 )      ( L'0 S') ( f2 )   ( f1 )
+*     (    ) = (       )   (    )  =>  (       ) (    ) = (    )
+*     ( g2 )   ( 0   I )   ( g1 )      ( 0   I ) ( g2 )   ( g1 )
+*
+*     from which it follows that:
+*
+*     { L'0 * f2 + S' * g2 = f1
+*     {                          =>  f2 = inv(L'0) * ( f1 - S' * g2)
+*     {                 g2 = g1
+*
+*  4. Compute
+*
+*     ( x )     ( f2 )
+*     (   ) = P (    )
+*     ( y )     ( g2 )                                                */
+
+void lpf_btran(LPF *lpf, double x[])
+{     int m0 = lpf->m0;
+      int m = lpf->m;
+      int n = lpf->n;
+      int *P_row = lpf->P_row;
+      int *Q_row = lpf->Q_row;
+      double *fg = lpf->work1;
+      double *f = fg;
+      double *g = fg + m0;
+      int i, ii;
+#if _GLPLPF_DEBUG
+      double *b;
+#endif
+      if (!lpf->valid)
+         xfault("lpf_btran: the factorization is not valid\n");
+      xassert(0 <= m && m <= m0 + n);
+#if _GLPLPF_DEBUG
+      /* save the right-hand side vector */
+      b = xcalloc(1+m, sizeof(double));
+      for (i = 1; i <= m; i++) b[i] = x[i];
+#endif
+      /* (f g) := Q * (b 0) */
+      for (i = 1; i <= m0 + n; i++)
+         fg[i] = ((ii = Q_row[i]) <= m ? x[ii] : 0.0);
+      /* f1 := inv(U'0) * f */
+      luf_v_solve(lpf->luf, 1, f);
+      /* g1 := inv(C') * (g - R' * f1) */
+      rt_prod(lpf, g, -1.0, f);
+      scf_solve_it(lpf->scf, 1, g);
+      /* g2 := g1 */
+      g = g;
+      /* f2 := inv(L'0) * (f1 - S' * g2) */
+      st_prod(lpf, f, -1.0, g);
+      luf_f_solve(lpf->luf, 1, f);
+      /* (x y) := P * (f2 g2) */
+      for (i = 1; i <= m; i++)
+         x[i] = fg[P_row[i]];
+#if _GLPLPF_DEBUG
+      /* check relative error in solution */
+      check_error(lpf, 1, x, b);
+      xfree(b);
+#endif
+      return;
+}
+
+/***********************************************************************
+*  The routine enlarge_sva enlarges the Sparse Vector Area to new_size
+*  locations by reallocating the arrays v_ind and v_val. */
+
+static void enlarge_sva(LPF *lpf, int new_size)
+{     int v_size = lpf->v_size;
+      int used = lpf->v_ptr - 1;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      xassert(v_size < new_size);
+      while (v_size < new_size) v_size += v_size;
+      lpf->v_size = v_size;
+      lpf->v_ind = xcalloc(1+v_size, sizeof(int));
+      lpf->v_val = xcalloc(1+v_size, sizeof(double));
+      xassert(used >= 0);
+      memcpy(&lpf->v_ind[1], &v_ind[1], used * sizeof(int));
+      memcpy(&lpf->v_val[1], &v_val[1], used * sizeof(double));
+      xfree(v_ind);
+      xfree(v_val);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_update_it - update LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
+*     const double val[]);
+*
+*  DESCRIPTION
+*
+*  The routine lpf_update_it updates the factorization of the basis
+*  matrix B after replacing its j-th column by a new vector.
+*
+*  The parameter j specifies the number of column of B, which has been
+*  replaced, 1 <= j <= m, where m is the order of B.
+*
+*  The parameter bh specifies the basis header entry for the new column
+*  of B, which is the number of the new column in some original matrix.
+*  This parameter is optional and can be specified as 0.
+*
+*  Row indices and numerical values of non-zero elements of the new
+*  column of B should be placed in locations ind[1], ..., ind[len] and
+*  val[1], ..., val[len], resp., where len is the number of non-zeros
+*  in the column. Neither zero nor duplicate elements are allowed.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  LPF_ESING
+*     New basis B is singular within the working precision.
+*
+*  LPF_ELIMIT
+*     Maximal number of additional rows and columns has been reached.
+*
+*  BACKGROUND
+*
+*  Let j-th column of the current basis matrix B have to be replaced by
+*  a new column a. This replacement is equivalent to removing the old
+*  j-th column by fixing it at zero and introducing the new column as
+*  follows:
+*
+*                   ( B   F^| a )
+*     ( B  F^)      (       |   )
+*     (      ) ---> ( G^  H^| 0 )
+*     ( G^ H^)      (-------+---)
+*                   ( e'j 0 | 0 )
+*
+*  where ej is a unit vector with 1 in j-th position which used to fix
+*  the old j-th column of B (at zero). Then using the main equality we
+*  have:
+*
+*     ( B   F^| a )            ( B0  F | f )
+*     (       |   )   ( P  0 ) (       |   ) ( Q  0 )
+*     ( G^  H^| 0 ) = (      ) ( G   H | g ) (      ) =
+*     (-------+---)   ( 0  1 ) (-------+---) ( 0  1 )
+*     ( e'j 0 | 0 )            ( v'  w'| 0 )
+*
+*       [   ( B0  F )|   ( f ) ]            [   ( B0 F )  |   ( f ) ]
+*       [ P (       )| P (   ) ] ( Q  0 )   [ P (      ) Q| P (   ) ]
+*     = [   ( G   H )|   ( g ) ] (      ) = [   ( G  H )  |   ( g ) ]
+*       [------------+-------- ] ( 0  1 )   [-------------+---------]
+*       [   ( v'  w')|     0   ]            [   ( v' w') Q|    0    ]
+*
+*  where:
+*
+*     ( a )     ( f )      ( f )        ( a )
+*     (   ) = P (   )  =>  (   ) = P' * (   )
+*     ( 0 )     ( g )      ( g )        ( 0 )
+*
+*                                 ( ej )      ( v )    ( v )     ( ej )
+*     ( e'j  0 ) = ( v' w' ) Q => (    ) = Q' (   ) => (   ) = Q (    )
+*                                 ( 0  )      ( w )    ( w )     ( 0  )
+*
+*  On the other hand:
+*
+*              ( B0| F  f )
+*     ( P  0 ) (---+------) ( Q  0 )         ( B0    new F )
+*     (      ) ( G | H  g ) (      ) = new P (             ) new Q
+*     ( 0  1 ) (   |      ) ( 0  1 )         ( new G new H )
+*              ( v'| w' 0 )
+*
+*  where:
+*                               ( G )           ( H  g )
+*     new F = ( F  f ), new G = (   ),  new H = (      ),
+*                               ( v')           ( w' 0 )
+*
+*             ( P  0 )           ( Q  0 )
+*     new P = (      ) , new Q = (      ) .
+*             ( 0  1 )           ( 0  1 )
+*
+*  The factorization structure for the new augmented matrix remains the
+*  same, therefore:
+*
+*           ( B0    new F )         ( L0     0 ) ( U0 new R )
+*     new P (             ) new Q = (          ) (          )
+*           ( new G new H )         ( new S  I ) ( 0  new C )
+*
+*  where:
+*
+*     new F = L0 * new R  =>
+*
+*     new R = inv(L0) * new F = inv(L0) * (F  f) = ( R  inv(L0)*f )
+*
+*     new G = new S * U0  =>
+*
+*                               ( G )             (     S      )
+*     new S = new G * inv(U0) = (   ) * inv(U0) = (            )
+*                               ( v')             ( v'*inv(U0) )
+*
+*     new H = new S * new R + new C  =>
+*
+*     new C = new H - new S * new R =
+*
+*             ( H  g )   (     S      )
+*           = (      ) - (            ) * ( R  inv(L0)*f ) =
+*             ( w' 0 )   ( v'*inv(U0) )
+*
+*             ( H - S*R           g - S*inv(L0)*f      )   ( C  x )
+*           = (                                        ) = (      )
+*             ( w'- v'*inv(U0)*R  -v'*inv(U0)*inv(L0)*f)   ( y' z )
+*
+*  Note that new C is resulted by expanding old C with new column x,
+*  row y', and diagonal element z, where:
+*
+*     x = g - S * inv(L0) * f = g - S * (new column of R)
+*
+*     y = w - R'* inv(U'0)* v = w - R'* (new row of S)
+*
+*     z = - (new row of S) * (new column of R)
+*
+*  Finally, to replace old B by new B we have to permute j-th and last
+*  (just added) columns of the matrix
+*
+*     ( B   F^| a )
+*     (       |   )
+*     ( G^  H^| 0 )
+*     (-------+---)
+*     ( e'j 0 | 0 )
+*
+*  and to keep the main equality do the same for matrix Q. */
+
+int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
+      const double val[])
+{     int m0 = lpf->m0;
+      int m = lpf->m;
+#if _GLPLPF_DEBUG
+      double *B = lpf->B;
+#endif
+      int n = lpf->n;
+      int *R_ptr = lpf->R_ptr;
+      int *R_len = lpf->R_len;
+      int *S_ptr = lpf->S_ptr;
+      int *S_len = lpf->S_len;
+      int *P_row = lpf->P_row;
+      int *P_col = lpf->P_col;
+      int *Q_row = lpf->Q_row;
+      int *Q_col = lpf->Q_col;
+      int v_ptr = lpf->v_ptr;
+      int *v_ind = lpf->v_ind;
+      double *v_val = lpf->v_val;
+      double *a = lpf->work2; /* new column */
+      double *fg = lpf->work1, *f = fg, *g = fg + m0;
+      double *vw = lpf->work2, *v = vw, *w = vw + m0;
+      double *x = g, *y = w, z;
+      int i, ii, k, ret;
+      xassert(bh == bh);
+      if (!lpf->valid)
+         xfault("lpf_update_it: the factorization is not valid\n");
+      if (!(1 <= j && j <= m))
+         xfault("lpf_update_it: j = %d; column number out of range\n",
+            j);
+      xassert(0 <= m && m <= m0 + n);
+      /* check if the basis factorization can be expanded */
+      if (n == lpf->n_max)
+      {  lpf->valid = 0;
+         ret = LPF_ELIMIT;
+         goto done;
+      }
+      /* convert new j-th column of B to dense format */
+      for (i = 1; i <= m; i++)
+         a[i] = 0.0;
+      for (k = 1; k <= len; k++)
+      {  i = ind[k];
+         if (!(1 <= i && i <= m))
+            xfault("lpf_update_it: ind[%d] = %d; row number out of rang"
+               "e\n", k, i);
+         if (a[i] != 0.0)
+            xfault("lpf_update_it: ind[%d] = %d; duplicate row index no"
+               "t allowed\n", k, i);
+         if (val[k] == 0.0)
+            xfault("lpf_update_it: val[%d] = %g; zero element not allow"
+               "ed\n", k, val[k]);
+         a[i] = val[k];
+      }
+#if _GLPLPF_DEBUG
+      /* change column in the basis matrix for debugging */
+      for (i = 1; i <= m; i++)
+         B[(i - 1) * m + j] = a[i];
+#endif
+      /* (f g) := inv(P) * (a 0) */
+      for (i = 1; i <= m0+n; i++)
+         fg[i] = ((ii = P_col[i]) <= m ? a[ii] : 0.0);
+      /* (v w) := Q * (ej 0) */
+      for (i = 1; i <= m0+n; i++) vw[i] = 0.0;
+      vw[Q_col[j]] = 1.0;
+      /* f1 := inv(L0) * f (new column of R) */
+      luf_f_solve(lpf->luf, 0, f);
+      /* v1 := inv(U'0) * v (new row of S) */
+      luf_v_solve(lpf->luf, 1, v);
+      /* we need at most 2 * m0 available locations in the SVA to store
+         new column of matrix R and new row of matrix S */
+      if (lpf->v_size < v_ptr + m0 + m0)
+      {  enlarge_sva(lpf, v_ptr + m0 + m0);
+         v_ind = lpf->v_ind;
+         v_val = lpf->v_val;
+      }
+      /* store new column of R */
+      R_ptr[n+1] = v_ptr;
+      for (i = 1; i <= m0; i++)
+      {  if (f[i] != 0.0)
+            v_ind[v_ptr] = i, v_val[v_ptr] = f[i], v_ptr++;
+      }
+      R_len[n+1] = v_ptr - lpf->v_ptr;
+      lpf->v_ptr = v_ptr;
+      /* store new row of S */
+      S_ptr[n+1] = v_ptr;
+      for (i = 1; i <= m0; i++)
+      {  if (v[i] != 0.0)
+            v_ind[v_ptr] = i, v_val[v_ptr] = v[i], v_ptr++;
+      }
+      S_len[n+1] = v_ptr - lpf->v_ptr;
+      lpf->v_ptr = v_ptr;
+      /* x := g - S * f1 (new column of C) */
+      s_prod(lpf, x, -1.0, f);
+      /* y := w - R' * v1 (new row of C) */
+      rt_prod(lpf, y, -1.0, v);
+      /* z := - v1 * f1 (new diagonal element of C) */
+      z = 0.0;
+      for (i = 1; i <= m0; i++) z -= v[i] * f[i];
+      /* update factorization of new matrix C */
+      switch (scf_update_exp(lpf->scf, x, y, z))
+      {  case 0:
+            break;
+         case SCF_ESING:
+            lpf->valid = 0;
+            ret = LPF_ESING;
+            goto done;
+         case SCF_ELIMIT:
+            xassert(lpf != lpf);
+         default:
+            xassert(lpf != lpf);
+      }
+      /* expand matrix P */
+      P_row[m0+n+1] = P_col[m0+n+1] = m0+n+1;
+      /* expand matrix Q */
+      Q_row[m0+n+1] = Q_col[m0+n+1] = m0+n+1;
+      /* permute j-th and last (just added) column of matrix Q */
+      i = Q_col[j], ii = Q_col[m0+n+1];
+      Q_row[i] = m0+n+1, Q_col[m0+n+1] = i;
+      Q_row[ii] = j, Q_col[j] = ii;
+      /* increase the number of additional rows and columns */
+      lpf->n++;
+      xassert(lpf->n <= lpf->n_max);
+      /* the factorization has been successfully updated */
+      ret = 0;
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  lpf_delete_it - delete LP basis factorization
+*
+*  SYNOPSIS
+*
+*  #include "glplpf.h"
+*  void lpf_delete_it(LPF *lpf)
+*
+*  DESCRIPTION
+*
+*  The routine lpf_delete_it deletes LP basis factorization specified
+*  by the parameter lpf and frees all memory allocated to this program
+*  object. */
+
+void lpf_delete_it(LPF *lpf)
+{     luf_delete_it(lpf->luf);
+#if _GLPLPF_DEBUG
+      if (lpf->B != NULL) xfree(lpf->B);
+#else
+      xassert(lpf->B == NULL);
+#endif
+      if (lpf->R_ptr != NULL) xfree(lpf->R_ptr);
+      if (lpf->R_len != NULL) xfree(lpf->R_len);
+      if (lpf->S_ptr != NULL) xfree(lpf->S_ptr);
+      if (lpf->S_len != NULL) xfree(lpf->S_len);
+      if (lpf->scf != NULL) scf_delete_it(lpf->scf);
+      if (lpf->P_row != NULL) xfree(lpf->P_row);
+      if (lpf->P_col != NULL) xfree(lpf->P_col);
+      if (lpf->Q_row != NULL) xfree(lpf->Q_row);
+      if (lpf->Q_col != NULL) xfree(lpf->Q_col);
+      if (lpf->v_ind != NULL) xfree(lpf->v_ind);
+      if (lpf->v_val != NULL) xfree(lpf->v_val);
+      if (lpf->work1 != NULL) xfree(lpf->work1);
+      if (lpf->work2 != NULL) xfree(lpf->work2);
+      xfree(lpf);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glplpf.h
===================================================================
--- deps/glpk/src/glplpf.h	(revision 9)
+++ deps/glpk/src/glplpf.h	(revision 9)
@@ -0,0 +1,194 @@
+/* glplpf.h (LP basis factorization, Schur complement version) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPLPF_H
+#define GLPLPF_H
+
+#include "glpscf.h"
+#include "glpluf.h"
+
+/***********************************************************************
+*  The structure LPF defines the factorization of the basis mxm matrix
+*  B, where m is the number of rows in corresponding problem instance.
+*
+*  This factorization is the following septet:
+*
+*     [B] = (L0, U0, R, S, C, P, Q),                                 (1)
+*
+*  and is based on the following main equality:
+*
+*     ( B  F^)     ( B0 F )       ( L0 0 ) ( U0 R )
+*     (      ) = P (      ) Q = P (      ) (      ) Q,               (2)
+*     ( G^ H^)     ( G  H )       ( S  I ) ( 0  C )
+*
+*  where:
+*
+*  B is the current basis matrix (not stored);
+*
+*  F^, G^, H^ are some additional matrices (not stored);
+*
+*  B0 is some initial basis matrix (not stored);
+*
+*  F, G, H are some additional matrices (not stored);
+*
+*  P, Q are permutation matrices (stored in both row- and column-like
+*  formats);
+*
+*  L0, U0 are some matrices that defines a factorization of the initial
+*  basis matrix B0 = L0 * U0 (stored in an invertable form);
+*
+*  R is a matrix defined from L0 * R = F, so R = inv(L0) * F (stored in
+*  a column-wise sparse format);
+*
+*  S is a matrix defined from S * U0 = G, so S = G * inv(U0) (stored in
+*  a row-wise sparse format);
+*
+*  C is the Schur complement for matrix (B0 F G H). It is defined from
+*  S * R + C = H, so C = H - S * R = H - G * inv(U0) * inv(L0) * F =
+*  = H - G * inv(B0) * F. Matrix C is stored in an invertable form.
+*
+*  REFERENCES
+*
+*  1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
+*     tion," SCCM, Stanford University, 2006.
+*
+*  2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
+*     sity, Spring 2006.
+*
+*  3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
+*     ibid. */
+
+typedef struct LPF LPF;
+
+struct LPF
+{     /* LP basis factorization */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      /*--------------------------------------------------------------*/
+      /* initial basis matrix B0 */
+      int m0_max;
+      /* maximal value of m0 (increased automatically, if necessary) */
+      int m0;
+      /* the order of B0 */
+      LUF *luf;
+      /* LU-factorization of B0 */
+      /*--------------------------------------------------------------*/
+      /* current basis matrix B */
+      int m;
+      /* the order of B */
+      double *B; /* double B[1+m*m]; */
+      /* B in dense format stored by rows and used only for debugging;
+         normally this array is not allocated */
+      /*--------------------------------------------------------------*/
+      /* augmented matrix (B0 F G H) of the order m0+n */
+      int n_max;
+      /* maximal number of additional rows and columns */
+      int n;
+      /* current number of additional rows and columns */
+      /*--------------------------------------------------------------*/
+      /* m0xn matrix R in column-wise format */
+      int *R_ptr; /* int R_ptr[1+n_max]; */
+      /* R_ptr[j], 1 <= j <= n, is a pointer to j-th column */
+      int *R_len; /* int R_len[1+n_max]; */
+      /* R_len[j], 1 <= j <= n, is the length of j-th column */
+      /*--------------------------------------------------------------*/
+      /* nxm0 matrix S in row-wise format */
+      int *S_ptr; /* int S_ptr[1+n_max]; */
+      /* S_ptr[i], 1 <= i <= n, is a pointer to i-th row */
+      int *S_len; /* int S_len[1+n_max]; */
+      /* S_len[i], 1 <= i <= n, is the length of i-th row */
+      /*--------------------------------------------------------------*/
+      /* Schur complement C of the order n */
+      SCF *scf; /* SCF scf[1:n_max]; */
+      /* factorization of the Schur complement */
+      /*--------------------------------------------------------------*/
+      /* matrix P of the order m0+n */
+      int *P_row; /* int P_row[1+m0_max+n_max]; */
+      /* P_row[i] = j means that P[i,j] = 1 */
+      int *P_col; /* int P_col[1+m0_max+n_max]; */
+      /* P_col[j] = i means that P[i,j] = 1 */
+      /*--------------------------------------------------------------*/
+      /* matrix Q of the order m0+n */
+      int *Q_row; /* int Q_row[1+m0_max+n_max]; */
+      /* Q_row[i] = j means that Q[i,j] = 1 */
+      int *Q_col; /* int Q_col[1+m0_max+n_max]; */
+      /* Q_col[j] = i means that Q[i,j] = 1 */
+      /*--------------------------------------------------------------*/
+      /* Sparse Vector Area (SVA) is a set of locations intended to
+         store sparse vectors which represent columns of matrix R and
+         rows of matrix S; each location is a doublet (ind, val), where
+         ind is an index, val is a numerical value of a sparse vector
+         element; in the whole each sparse vector is a set of adjacent
+         locations defined by a pointer to its first element and its
+         length, i.e. the number of its elements */
+      int v_size;
+      /* the SVA size, in locations; locations are numbered by integers
+         1, 2, ..., v_size, and location 0 is not used */
+      int v_ptr;
+      /* pointer to the first available location */
+      int *v_ind; /* int v_ind[1+v_size]; */
+      /* v_ind[k], 1 <= k <= v_size, is the index field of location k */
+      double *v_val; /* double v_val[1+v_size]; */
+      /* v_val[k], 1 <= k <= v_size, is the value field of location k */
+      /*--------------------------------------------------------------*/
+      double *work1; /* double work1[1+m0+n_max]; */
+      /* working array */
+      double *work2; /* double work2[1+m0+n_max]; */
+      /* working array */
+};
+
+/* return codes: */
+#define LPF_ESING    1  /* singular matrix */
+#define LPF_ECOND    2  /* ill-conditioned matrix */
+#define LPF_ELIMIT   3  /* update limit reached */
+
+#define lpf_create_it _glp_lpf_create_it
+LPF *lpf_create_it(void);
+/* create LP basis factorization */
+
+#define lpf_factorize _glp_lpf_factorize
+int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
+      (void *info, int j, int ind[], double val[]), void *info);
+/* compute LP basis factorization */
+
+#define lpf_ftran _glp_lpf_ftran
+void lpf_ftran(LPF *lpf, double x[]);
+/* perform forward transformation (solve system B*x = b) */
+
+#define lpf_btran _glp_lpf_btran
+void lpf_btran(LPF *lpf, double x[]);
+/* perform backward transformation (solve system B'*x = b) */
+
+#define lpf_update_it _glp_lpf_update_it
+int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
+      const double val[]);
+/* update LP basis factorization */
+
+#define lpf_delete_it _glp_lpf_delete_it
+void lpf_delete_it(LPF *lpf);
+/* delete LP basis factorization */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glplpx01.c
===================================================================
--- deps/glpk/src/glplpx01.c	(revision 9)
+++ deps/glpk/src/glplpx01.c	(revision 9)
@@ -0,0 +1,1542 @@
+/* glplpx01.c (obsolete API routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+struct LPXCPS
+{     /* control parameters and statistics */
+      int msg_lev;
+      /* level of messages output by the solver:
+         0 - no output
+         1 - error messages only
+         2 - normal output
+         3 - full output (includes informational messages) */
+      int scale;
+      /* scaling option:
+         0 - no scaling
+         1 - equilibration scaling
+         2 - geometric mean scaling
+         3 - geometric mean scaling, then equilibration scaling */
+      int dual;
+      /* dual simplex option:
+         0 - use primal simplex
+         1 - use dual simplex */
+      int price;
+      /* pricing option (for both primal and dual simplex):
+         0 - textbook pricing
+         1 - steepest edge pricing */
+      double relax;
+      /* relaxation parameter used in the ratio test; if it is zero,
+         the textbook ratio test is used; if it is non-zero (should be
+         positive), Harris' two-pass ratio test is used; in the latter
+         case on the first pass basic variables (in the case of primal
+         simplex) or reduced costs of non-basic variables (in the case
+         of dual simplex) are allowed to slightly violate their bounds,
+         but not more than (relax * tol_bnd) or (relax * tol_dj) (thus,
+         relax is a percentage of tol_bnd or tol_dj) */
+      double tol_bnd;
+      /* relative tolerance used to check if the current basic solution
+         is primal feasible */
+      double tol_dj;
+      /* absolute tolerance used to check if the current basic solution
+         is dual feasible */
+      double tol_piv;
+      /* relative tolerance used to choose eligible pivotal elements of
+         the simplex table in the ratio test */
+      int round;
+      /* solution rounding option:
+         0 - report all computed values and reduced costs "as is"
+         1 - if possible (allowed by the tolerances), replace computed
+             values and reduced costs which are close to zero by exact
+             zeros */
+      double obj_ll;
+      /* lower limit of the objective function; if on the phase II the
+         objective function reaches this limit and continues decreasing,
+         the solver stops the search */
+      double obj_ul;
+      /* upper limit of the objective function; if on the phase II the
+         objective function reaches this limit and continues increasing,
+         the solver stops the search */
+      int it_lim;
+      /* simplex iterations limit; if this value is positive, it is
+         decreased by one each time when one simplex iteration has been
+         performed, and reaching zero value signals the solver to stop
+         the search; negative value means no iterations limit */
+      double tm_lim;
+      /* searching time limit, in seconds; if this value is positive,
+         it is decreased each time when one simplex iteration has been
+         performed by the amount of time spent for the iteration, and
+         reaching zero value signals the solver to stop the search;
+         negative value means no time limit */
+      int out_frq;
+      /* output frequency, in iterations; this parameter specifies how
+         frequently the solver sends information about the solution to
+         the standard output */
+      double out_dly;
+      /* output delay, in seconds; this parameter specifies how long
+         the solver should delay sending information about the solution
+         to the standard output; zero value means no delay */
+      int branch; /* MIP */
+      /* branching heuristic:
+         0 - branch on first variable
+         1 - branch on last variable
+         2 - branch using heuristic by Driebeck and Tomlin
+         3 - branch on most fractional variable */
+      int btrack; /* MIP */
+      /* backtracking heuristic:
+         0 - select most recent node (depth first search)
+         1 - select earliest node (breadth first search)
+         2 - select node using the best projection heuristic
+         3 - select node with best local bound */
+      double tol_int; /* MIP */
+      /* absolute tolerance used to check if the current basic solution
+         is integer feasible */
+      double tol_obj; /* MIP */
+      /* relative tolerance used to check if the value of the objective
+         function is not better than in the best known integer feasible
+         solution */
+      int mps_info; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps outputs several
+         comment cards that contains some information about the problem;
+         otherwise the routine outputs no comment cards */
+      int mps_obj; /* lpx_write_mps */
+      /* this parameter tells the routine lpx_write_mps how to output
+         the objective function row:
+         0 - never output objective function row
+         1 - always output objective function row
+         2 - output objective function row if and only if the problem
+             has no free rows */
+      int mps_orig; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps uses original
+         row and column symbolic names; otherwise the routine generates
+         plain names using ordinal numbers of rows and columns */
+      int mps_wide; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps uses all data
+         fields; otherwise the routine keeps fields 5 and 6 empty */
+      int mps_free; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps omits column
+         and vector names everytime if possible (free style); otherwise
+         the routine never omits these names (pedantic style) */
+      int mps_skip; /* lpx_write_mps */
+      /* if this flag is set, the routine lpx_write_mps skips empty
+         columns (i.e. which has no constraint coefficients); otherwise
+         the routine outputs all columns */
+      int lpt_orig; /* lpx_write_lpt */
+      /* if this flag is set, the routine lpx_write_lpt uses original
+         row and column symbolic names; otherwise the routine generates
+         plain names using ordinal numbers of rows and columns */
+      int presol; /* lpx_simplex */
+      /* LP presolver option:
+         0 - do not use LP presolver
+         1 - use LP presolver */
+      int binarize; /* lpx_intopt */
+      /* if this flag is set, the routine lpx_intopt replaces integer
+         columns by binary ones */
+      int use_cuts; /* lpx_intopt */
+      /* if this flag is set, the routine lpx_intopt tries generating
+         cutting planes:
+         LPX_C_COVER  - mixed cover cuts
+         LPX_C_CLIQUE - clique cuts
+         LPX_C_GOMORY - Gomory's mixed integer cuts
+         LPX_C_ALL    - all cuts */
+      double mip_gap; /* MIP */
+      /* relative MIP gap tolerance */
+};
+
+LPX *lpx_create_prob(void)
+{     /* create problem object */
+      return glp_create_prob();
+}
+
+void lpx_set_prob_name(LPX *lp, const char *name)
+{     /* assign (change) problem name */
+      glp_set_prob_name(lp, name);
+      return;
+}
+
+void lpx_set_obj_name(LPX *lp, const char *name)
+{     /* assign (change) objective function name */
+      glp_set_obj_name(lp, name);
+      return;
+}
+
+void lpx_set_obj_dir(LPX *lp, int dir)
+{     /* set (change) optimization direction flag */
+      glp_set_obj_dir(lp, dir - LPX_MIN + GLP_MIN);
+      return;
+}
+
+int lpx_add_rows(LPX *lp, int nrs)
+{     /* add new rows to problem object */
+      return glp_add_rows(lp, nrs);
+}
+
+int lpx_add_cols(LPX *lp, int ncs)
+{     /* add new columns to problem object */
+      return glp_add_cols(lp, ncs);
+}
+
+void lpx_set_row_name(LPX *lp, int i, const char *name)
+{     /* assign (change) row name */
+      glp_set_row_name(lp, i, name);
+      return;
+}
+
+void lpx_set_col_name(LPX *lp, int j, const char *name)
+{     /* assign (change) column name */
+      glp_set_col_name(lp, j, name);
+      return;
+}
+
+void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub)
+{     /* set (change) row bounds */
+      glp_set_row_bnds(lp, i, type - LPX_FR + GLP_FR, lb, ub);
+      return;
+}
+
+void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub)
+{     /* set (change) column bounds */
+      glp_set_col_bnds(lp, j, type - LPX_FR + GLP_FR, lb, ub);
+      return;
+}
+
+void lpx_set_obj_coef(glp_prob *lp, int j, double coef)
+{     /* set (change) obj. coefficient or constant term */
+      glp_set_obj_coef(lp, j, coef);
+      return;
+}
+
+void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[],
+      const double val[])
+{     /* set (replace) row of the constraint matrix */
+      glp_set_mat_row(lp, i, len, ind, val);
+      return;
+}
+
+void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[],
+      const double val[])
+{     /* set (replace) column of the constraint matrix */
+      glp_set_mat_col(lp, j, len, ind, val);
+      return;
+}
+
+void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[],
+      const double ar[])
+{     /* load (replace) the whole constraint matrix */
+      glp_load_matrix(lp, ne, ia, ja, ar);
+      return;
+}
+
+void lpx_del_rows(LPX *lp, int nrs, const int num[])
+{     /* delete specified rows from problem object */
+      glp_del_rows(lp, nrs, num);
+      return;
+}
+
+void lpx_del_cols(LPX *lp, int ncs, const int num[])
+{     /* delete specified columns from problem object */
+      glp_del_cols(lp, ncs, num);
+      return;
+}
+
+void lpx_delete_prob(LPX *lp)
+{     /* delete problem object */
+      glp_delete_prob(lp);
+      return;
+}
+
+const char *lpx_get_prob_name(LPX *lp)
+{     /* retrieve problem name */
+      return glp_get_prob_name(lp);
+}
+
+const char *lpx_get_obj_name(LPX *lp)
+{     /* retrieve objective function name */
+      return glp_get_obj_name(lp);
+}
+
+int lpx_get_obj_dir(LPX *lp)
+{     /* retrieve optimization direction flag */
+      return glp_get_obj_dir(lp) - GLP_MIN + LPX_MIN;
+}
+
+int lpx_get_num_rows(LPX *lp)
+{     /* retrieve number of rows */
+      return glp_get_num_rows(lp);
+}
+
+int lpx_get_num_cols(LPX *lp)
+{     /* retrieve number of columns */
+      return glp_get_num_cols(lp);
+}
+
+const char *lpx_get_row_name(LPX *lp, int i)
+{     /* retrieve row name */
+      return glp_get_row_name(lp, i);
+}
+
+const char *lpx_get_col_name(LPX *lp, int j)
+{     /* retrieve column name */
+      return glp_get_col_name(lp, j);
+}
+
+int lpx_get_row_type(LPX *lp, int i)
+{     /* retrieve row type */
+      return glp_get_row_type(lp, i) - GLP_FR + LPX_FR;
+}
+
+double lpx_get_row_lb(glp_prob *lp, int i)
+{     /* retrieve row lower bound */
+      double lb;
+      lb = glp_get_row_lb(lp, i);
+      if (lb == -DBL_MAX) lb = 0.0;
+      return lb;
+}
+
+double lpx_get_row_ub(glp_prob *lp, int i)
+{     /* retrieve row upper bound */
+      double ub;
+      ub = glp_get_row_ub(lp, i);
+      if (ub == +DBL_MAX) ub = 0.0;
+      return ub;
+}
+
+void lpx_get_row_bnds(glp_prob *lp, int i, int *typx, double *lb,
+      double *ub)
+{     /* retrieve row bounds */
+      if (typx != NULL) *typx = lpx_get_row_type(lp, i);
+      if (lb != NULL) *lb = lpx_get_row_lb(lp, i);
+      if (ub != NULL) *ub = lpx_get_row_ub(lp, i);
+      return;
+}
+
+int lpx_get_col_type(LPX *lp, int j)
+{     /* retrieve column type */
+      return glp_get_col_type(lp, j) - GLP_FR + LPX_FR;
+}
+
+double lpx_get_col_lb(glp_prob *lp, int j)
+{     /* retrieve column lower bound */
+      double lb;
+      lb = glp_get_col_lb(lp, j);
+      if (lb == -DBL_MAX) lb = 0.0;
+      return lb;
+}
+
+double lpx_get_col_ub(glp_prob *lp, int j)
+{     /* retrieve column upper bound */
+      double ub;
+      ub = glp_get_col_ub(lp, j);
+      if (ub == +DBL_MAX) ub = 0.0;
+      return ub;
+}
+
+void lpx_get_col_bnds(glp_prob *lp, int j, int *typx, double *lb,
+      double *ub)
+{     /* retrieve column bounds */
+      if (typx != NULL) *typx = lpx_get_col_type(lp, j);
+      if (lb != NULL) *lb = lpx_get_col_lb(lp, j);
+      if (ub != NULL) *ub = lpx_get_col_ub(lp, j);
+      return;
+}
+
+double lpx_get_obj_coef(LPX *lp, int j)
+{     /* retrieve obj. coefficient or constant term */
+      return glp_get_obj_coef(lp, j);
+}
+
+int lpx_get_num_nz(LPX *lp)
+{     /* retrieve number of constraint coefficients */
+      return glp_get_num_nz(lp);
+}
+
+int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[])
+{     /* retrieve row of the constraint matrix */
+      return glp_get_mat_row(lp, i, ind, val);
+}
+
+int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[])
+{     /* retrieve column of the constraint matrix */
+      return glp_get_mat_col(lp, j, ind, val);
+}
+
+void lpx_create_index(LPX *lp)
+{     /* create the name index */
+      glp_create_index(lp);
+      return;
+}
+
+int lpx_find_row(LPX *lp, const char *name)
+{     /* find row by its name */
+      return glp_find_row(lp, name);
+}
+
+int lpx_find_col(LPX *lp, const char *name)
+{     /* find column by its name */
+      return glp_find_col(lp, name);
+}
+
+void lpx_delete_index(LPX *lp)
+{     /* delete the name index */
+      glp_delete_index(lp);
+      return;
+}
+
+void lpx_scale_prob(LPX *lp)
+{     /* scale problem data */
+      switch (lpx_get_int_parm(lp, LPX_K_SCALE))
+      {  case 0:
+            /* no scaling */
+            glp_unscale_prob(lp);
+            break;
+         case 1:
+            /* equilibration scaling */
+            glp_scale_prob(lp, GLP_SF_EQ);
+            break;
+         case 2:
+            /* geometric mean scaling */
+            glp_scale_prob(lp, GLP_SF_GM);
+            break;
+         case 3:
+            /* geometric mean scaling, then equilibration scaling */
+            glp_scale_prob(lp, GLP_SF_GM | GLP_SF_EQ);
+            break;
+         default:
+            xassert(lp != lp);
+      }
+      return;
+}
+
+void lpx_unscale_prob(LPX *lp)
+{     /* unscale problem data */
+      glp_unscale_prob(lp);
+      return;
+}
+
+void lpx_set_row_stat(LPX *lp, int i, int stat)
+{     /* set (change) row status */
+      glp_set_row_stat(lp, i, stat - LPX_BS + GLP_BS);
+      return;
+}
+
+void lpx_set_col_stat(LPX *lp, int j, int stat)
+{     /* set (change) column status */
+      glp_set_col_stat(lp, j, stat - LPX_BS + GLP_BS);
+      return;
+}
+
+void lpx_std_basis(LPX *lp)
+{     /* construct standard initial LP basis */
+      glp_std_basis(lp);
+      return;
+}
+
+void lpx_adv_basis(LPX *lp)
+{     /* construct advanced initial LP basis */
+      glp_adv_basis(lp, 0);
+      return;
+}
+
+void lpx_cpx_basis(LPX *lp)
+{     /* construct Bixby's initial LP basis */
+      glp_cpx_basis(lp);
+      return;
+}
+
+static void fill_smcp(LPX *lp, glp_smcp *parm)
+{     glp_init_smcp(parm);
+      switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
+      {  case 0:  parm->msg_lev = GLP_MSG_OFF;   break;
+         case 1:  parm->msg_lev = GLP_MSG_ERR;   break;
+         case 2:  parm->msg_lev = GLP_MSG_ON;    break;
+         case 3:  parm->msg_lev = GLP_MSG_ALL;   break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_DUAL))
+      {  case 0:  parm->meth = GLP_PRIMAL;       break;
+         case 1:  parm->meth = GLP_DUAL;         break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_PRICE))
+      {  case 0:  parm->pricing = GLP_PT_STD;    break;
+         case 1:  parm->pricing = GLP_PT_PSE;    break;
+         default: xassert(lp != lp);
+      }
+      if (lpx_get_real_parm(lp, LPX_K_RELAX) == 0.0)
+         parm->r_test = GLP_RT_STD;
+      else
+         parm->r_test = GLP_RT_HAR;
+      parm->tol_bnd = lpx_get_real_parm(lp, LPX_K_TOLBND);
+      parm->tol_dj  = lpx_get_real_parm(lp, LPX_K_TOLDJ);
+      parm->tol_piv = lpx_get_real_parm(lp, LPX_K_TOLPIV);
+      parm->obj_ll  = lpx_get_real_parm(lp, LPX_K_OBJLL);
+      parm->obj_ul  = lpx_get_real_parm(lp, LPX_K_OBJUL);
+      if (lpx_get_int_parm(lp, LPX_K_ITLIM) < 0)
+         parm->it_lim = INT_MAX;
+      else
+         parm->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM);
+      if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0)
+         parm->tm_lim = INT_MAX;
+      else
+         parm->tm_lim =
+            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
+      parm->out_frq = lpx_get_int_parm(lp, LPX_K_OUTFRQ);
+      parm->out_dly =
+            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_OUTDLY));
+      switch (lpx_get_int_parm(lp, LPX_K_PRESOL))
+      {  case 0:  parm->presolve = GLP_OFF;      break;
+         case 1:  parm->presolve = GLP_ON;       break;
+         default: xassert(lp != lp);
+      }
+      return;
+}
+
+int lpx_simplex(LPX *lp)
+{     /* easy-to-use driver to the simplex method */
+      glp_smcp parm;
+      int ret;
+      fill_smcp(lp, &parm);
+      ret = glp_simplex(lp, &parm);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_EBADB:
+         case GLP_ESING:
+         case GLP_ECOND:
+         case GLP_EBOUND:  ret = LPX_E_FAULT;   break;
+         case GLP_EFAIL:   ret = LPX_E_SING;    break;
+         case GLP_EOBJLL:  ret = LPX_E_OBJLL;   break;
+         case GLP_EOBJUL:  ret = LPX_E_OBJUL;   break;
+         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
+         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
+         case GLP_ENOPFS:  ret = LPX_E_NOPFS;   break;
+         case GLP_ENODFS:  ret = LPX_E_NODFS;   break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_exact(LPX *lp)
+{     /* easy-to-use driver to the exact simplex method */
+      glp_smcp parm;
+      int ret;
+      fill_smcp(lp, &parm);
+      ret = glp_exact(lp, &parm);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_EBADB:
+         case GLP_ESING:
+         case GLP_EBOUND:
+         case GLP_EFAIL:   ret = LPX_E_FAULT;   break;
+         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
+         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_get_status(glp_prob *lp)
+{     /* retrieve generic status of basic solution */
+      int status;
+      switch (glp_get_status(lp))
+      {  case GLP_OPT:    status = LPX_OPT;    break;
+         case GLP_FEAS:   status = LPX_FEAS;   break;
+         case GLP_INFEAS: status = LPX_INFEAS; break;
+         case GLP_NOFEAS: status = LPX_NOFEAS; break;
+         case GLP_UNBND:  status = LPX_UNBND;  break;
+         case GLP_UNDEF:  status = LPX_UNDEF;  break;
+         default:         xassert(lp != lp);
+      }
+      return status;
+}
+
+int lpx_get_prim_stat(glp_prob *lp)
+{     /* retrieve status of primal basic solution */
+      return glp_get_prim_stat(lp) - GLP_UNDEF + LPX_P_UNDEF;
+}
+
+int lpx_get_dual_stat(glp_prob *lp)
+{     /* retrieve status of dual basic solution */
+      return glp_get_dual_stat(lp) - GLP_UNDEF + LPX_D_UNDEF;
+}
+
+double lpx_get_obj_val(LPX *lp)
+{     /* retrieve objective value (basic solution) */
+      return glp_get_obj_val(lp);
+}
+
+int lpx_get_row_stat(LPX *lp, int i)
+{     /* retrieve row status (basic solution) */
+      return glp_get_row_stat(lp, i) - GLP_BS + LPX_BS;
+}
+
+double lpx_get_row_prim(LPX *lp, int i)
+{     /* retrieve row primal value (basic solution) */
+      return glp_get_row_prim(lp, i);
+}
+
+double lpx_get_row_dual(LPX *lp, int i)
+{     /* retrieve row dual value (basic solution) */
+      return glp_get_row_dual(lp, i);
+}
+
+void lpx_get_row_info(glp_prob *lp, int i, int *tagx, double *vx,
+      double *dx)
+{     /* obtain row solution information */
+      if (tagx != NULL) *tagx = lpx_get_row_stat(lp, i);
+      if (vx != NULL) *vx = lpx_get_row_prim(lp, i);
+      if (dx != NULL) *dx = lpx_get_row_dual(lp, i);
+      return;
+}
+
+int lpx_get_col_stat(LPX *lp, int j)
+{     /* retrieve column status (basic solution) */
+      return glp_get_col_stat(lp, j) - GLP_BS + LPX_BS;
+}
+
+double lpx_get_col_prim(LPX *lp, int j)
+{     /* retrieve column primal value (basic solution) */
+      return glp_get_col_prim(lp, j);
+}
+
+double lpx_get_col_dual(glp_prob *lp, int j)
+{     /* retrieve column dual value (basic solution) */
+      return glp_get_col_dual(lp, j);
+}
+
+void lpx_get_col_info(glp_prob *lp, int j, int *tagx, double *vx,
+      double *dx)
+{     /* obtain column solution information */
+      if (tagx != NULL) *tagx = lpx_get_col_stat(lp, j);
+      if (vx != NULL) *vx = lpx_get_col_prim(lp, j);
+      if (dx != NULL) *dx = lpx_get_col_dual(lp, j);
+      return;
+}
+
+int lpx_get_ray_info(LPX *lp)
+{     /* determine what causes primal unboundness */
+      return glp_get_unbnd_ray(lp);
+}
+
+void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt)
+{     /* check Karush-Kuhn-Tucker conditions */
+      int ae_ind, re_ind;
+      double ae_max, re_max;
+      xassert(scaled == scaled);
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pe_ae_max = ae_max;
+      kkt->pe_ae_row = ae_ind;
+      kkt->pe_re_max = re_max;
+      kkt->pe_re_row = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pe_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pe_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pe_quality = 'L';
+      else
+         kkt->pe_quality = '?';
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pb_ae_max = ae_max;
+      kkt->pb_ae_ind = ae_ind;
+      kkt->pb_re_max = re_max;
+      kkt->pb_re_ind = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pb_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pb_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pb_quality = 'L';
+      else
+         kkt->pb_quality = '?';
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->de_ae_max = ae_max;
+      if (ae_ind == 0)
+         kkt->de_ae_col = 0;
+      else
+         kkt->de_ae_col = ae_ind - lp->m;
+      kkt->de_re_max = re_max;
+      if (re_ind == 0)
+         kkt->de_re_col = 0;
+      else
+         kkt->de_re_col = ae_ind - lp->m;
+      if (re_max <= 1e-9)
+         kkt->de_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->de_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->de_quality = 'L';
+      else
+         kkt->de_quality = '?';
+      _glp_check_kkt(lp, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->db_ae_max = ae_max;
+      kkt->db_ae_ind = ae_ind;
+      kkt->db_re_max = re_max;
+      kkt->db_re_ind = re_ind;
+      if (re_max <= 1e-9)
+         kkt->db_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->db_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->db_quality = 'L';
+      else
+         kkt->db_quality = '?';
+      kkt->cs_ae_max = 0.0, kkt->cs_ae_ind = 0;
+      kkt->cs_re_max = 0.0, kkt->cs_re_ind = 0;
+      kkt->cs_quality = 'H';
+      return;
+}
+
+int lpx_warm_up(LPX *lp)
+{     /* "warm up" LP basis */
+      int ret;
+      ret = glp_warm_up(lp);
+      if (ret == 0)
+         ret = LPX_E_OK;
+      else if (ret == GLP_EBADB)
+         ret = LPX_E_BADB;
+      else if (ret == GLP_ESING)
+         ret = LPX_E_SING;
+      else if (ret == GLP_ECOND)
+         ret = LPX_E_SING;
+      else
+         xassert(ret != ret);
+      return ret;
+}
+
+int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[])
+{     /* compute row of the simplex tableau */
+      return glp_eval_tab_row(lp, k, ind, val);
+}
+
+int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[])
+{     /* compute column of the simplex tableau */
+      return glp_eval_tab_col(lp, k, ind, val);
+}
+
+int lpx_transform_row(LPX *lp, int len, int ind[], double val[])
+{     /* transform explicitly specified row */
+      return glp_transform_row(lp, len, ind, val);
+}
+
+int lpx_transform_col(LPX *lp, int len, int ind[], double val[])
+{     /* transform explicitly specified column */
+      return glp_transform_col(lp, len, ind, val);
+}
+
+int lpx_prim_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol)
+{     /* perform primal ratio test */
+      int piv;
+      piv = glp_prim_rtest(lp, len, ind, val, how, tol);
+      xassert(0 <= piv && piv <= len);
+      return piv == 0 ? 0 : ind[piv];
+}
+
+int lpx_dual_ratio_test(LPX *lp, int len, const int ind[],
+      const double val[], int how, double tol)
+{     /* perform dual ratio test */
+      int piv;
+      piv = glp_dual_rtest(lp, len, ind, val, how, tol);
+      xassert(0 <= piv && piv <= len);
+      return piv == 0 ? 0 : ind[piv];
+}
+
+int lpx_interior(LPX *lp)
+{     /* easy-to-use driver to the interior-point method */
+      int ret;
+      ret = glp_interior(lp, NULL);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_EFAIL:   ret = LPX_E_FAULT;   break;
+         case GLP_ENOFEAS: ret = LPX_E_NOFEAS;  break;
+         case GLP_ENOCVG:  ret = LPX_E_NOCONV;  break;
+         case GLP_EITLIM:  ret = LPX_E_ITLIM;   break;
+         case GLP_EINSTAB: ret = LPX_E_INSTAB;  break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_ipt_status(glp_prob *lp)
+{     /* retrieve status of interior-point solution */
+      int status;
+      switch (glp_ipt_status(lp))
+      {  case GLP_UNDEF:  status = LPX_T_UNDEF;  break;
+         case GLP_OPT:    status = LPX_T_OPT;    break;
+         default:         xassert(lp != lp);
+      }
+      return status;
+}
+
+double lpx_ipt_obj_val(LPX *lp)
+{     /* retrieve objective value (interior point) */
+      return glp_ipt_obj_val(lp);
+}
+
+double lpx_ipt_row_prim(LPX *lp, int i)
+{     /* retrieve row primal value (interior point) */
+      return glp_ipt_row_prim(lp, i);
+}
+
+double lpx_ipt_row_dual(LPX *lp, int i)
+{     /* retrieve row dual value (interior point) */
+      return glp_ipt_row_dual(lp, i);
+}
+
+double lpx_ipt_col_prim(LPX *lp, int j)
+{     /* retrieve column primal value (interior point) */
+      return glp_ipt_col_prim(lp, j);
+}
+
+double lpx_ipt_col_dual(LPX *lp, int j)
+{     /* retrieve column dual value (interior point) */
+      return glp_ipt_col_dual(lp, j);
+}
+
+void lpx_set_class(LPX *lp, int klass)
+{     /* set problem class */
+      xassert(lp == lp);
+      if (!(klass == LPX_LP || klass == LPX_MIP))
+         xerror("lpx_set_class: invalid problem class\n");
+      return;
+}
+
+int lpx_get_class(LPX *lp)
+{     /* determine problem klass */
+      return glp_get_num_int(lp) == 0 ? LPX_LP : LPX_MIP;
+}
+
+void lpx_set_col_kind(LPX *lp, int j, int kind)
+{     /* set (change) column kind */
+      glp_set_col_kind(lp, j, kind - LPX_CV + GLP_CV);
+      return;
+}
+
+int lpx_get_col_kind(LPX *lp, int j)
+{     /* retrieve column kind */
+      return glp_get_col_kind(lp, j) == GLP_CV ? LPX_CV : LPX_IV;
+}
+
+int lpx_get_num_int(LPX *lp)
+{     /* retrieve number of integer columns */
+      return glp_get_num_int(lp);
+}
+
+int lpx_get_num_bin(LPX *lp)
+{     /* retrieve number of binary columns */
+      return glp_get_num_bin(lp);
+}
+
+static int solve_mip(LPX *lp, int presolve)
+{     glp_iocp parm;
+      int ret;
+      glp_init_iocp(&parm);
+      switch (lpx_get_int_parm(lp, LPX_K_MSGLEV))
+      {  case 0:  parm.msg_lev = GLP_MSG_OFF;   break;
+         case 1:  parm.msg_lev = GLP_MSG_ERR;   break;
+         case 2:  parm.msg_lev = GLP_MSG_ON;    break;
+         case 3:  parm.msg_lev = GLP_MSG_ALL;   break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_BRANCH))
+      {  case 0:  parm.br_tech = GLP_BR_FFV;    break;
+         case 1:  parm.br_tech = GLP_BR_LFV;    break;
+         case 2:  parm.br_tech = GLP_BR_DTH;    break;
+         case 3:  parm.br_tech = GLP_BR_MFV;    break;
+         default: xassert(lp != lp);
+      }
+      switch (lpx_get_int_parm(lp, LPX_K_BTRACK))
+      {  case 0:  parm.bt_tech = GLP_BT_DFS;    break;
+         case 1:  parm.bt_tech = GLP_BT_BFS;    break;
+         case 2:  parm.bt_tech = GLP_BT_BPH;    break;
+         case 3:  parm.bt_tech = GLP_BT_BLB;    break;
+         default: xassert(lp != lp);
+      }
+      parm.tol_int = lpx_get_real_parm(lp, LPX_K_TOLINT);
+      parm.tol_obj = lpx_get_real_parm(lp, LPX_K_TOLOBJ);
+      if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0 ||
+          lpx_get_real_parm(lp, LPX_K_TMLIM) > 1e6)
+         parm.tm_lim = INT_MAX;
+      else
+         parm.tm_lim =
+            (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM));
+      parm.mip_gap = lpx_get_real_parm(lp, LPX_K_MIPGAP);
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_GOMORY)
+         parm.gmi_cuts = GLP_ON;
+      else
+         parm.gmi_cuts = GLP_OFF;
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_MIR)
+         parm.mir_cuts = GLP_ON;
+      else
+         parm.mir_cuts = GLP_OFF;
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_COVER)
+         parm.cov_cuts = GLP_ON;
+      else
+         parm.cov_cuts = GLP_OFF;
+      if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_CLIQUE)
+         parm.clq_cuts = GLP_ON;
+      else
+         parm.clq_cuts = GLP_OFF;
+      parm.presolve = presolve;
+      if (lpx_get_int_parm(lp, LPX_K_BINARIZE))
+         parm.binarize = GLP_ON;
+      ret = glp_intopt(lp, &parm);
+      switch (ret)
+      {  case 0:           ret = LPX_E_OK;      break;
+         case GLP_ENOPFS:  ret = LPX_E_NOPFS;   break;
+         case GLP_ENODFS:  ret = LPX_E_NODFS;   break;
+         case GLP_EBOUND:
+         case GLP_EROOT:   ret = LPX_E_FAULT;   break;
+         case GLP_EFAIL:   ret = LPX_E_SING;    break;
+         case GLP_EMIPGAP: ret = LPX_E_MIPGAP;  break;
+         case GLP_ETMLIM:  ret = LPX_E_TMLIM;   break;
+         default:          xassert(ret != ret);
+      }
+      return ret;
+}
+
+int lpx_integer(LPX *lp)
+{     /* easy-to-use driver to the branch-and-bound method */
+      return solve_mip(lp, GLP_OFF);
+}
+
+int lpx_intopt(LPX *lp)
+{     /* easy-to-use driver to the branch-and-bound method */
+      return solve_mip(lp, GLP_ON);
+}
+
+int lpx_mip_status(glp_prob *lp)
+{     /* retrieve status of MIP solution */
+      int status;
+      switch (glp_mip_status(lp))
+      {  case GLP_UNDEF:  status = LPX_I_UNDEF;  break;
+         case GLP_OPT:    status = LPX_I_OPT;    break;
+         case GLP_FEAS:   status = LPX_I_FEAS;   break;
+         case GLP_NOFEAS: status = LPX_I_NOFEAS; break;
+         default:         xassert(lp != lp);
+      }
+      return status;
+}
+
+double lpx_mip_obj_val(LPX *lp)
+{     /* retrieve objective value (MIP solution) */
+      return glp_mip_obj_val(lp);
+}
+
+double lpx_mip_row_val(LPX *lp, int i)
+{     /* retrieve row value (MIP solution) */
+      return glp_mip_row_val(lp, i);
+}
+
+double lpx_mip_col_val(LPX *lp, int j)
+{     /* retrieve column value (MIP solution) */
+      return glp_mip_col_val(lp, j);
+}
+
+void lpx_check_int(LPX *lp, LPXKKT *kkt)
+{     /* check integer feasibility conditions */
+      int ae_ind, re_ind;
+      double ae_max, re_max;
+      _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pe_ae_max = ae_max;
+      kkt->pe_ae_row = ae_ind;
+      kkt->pe_re_max = re_max;
+      kkt->pe_re_row = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pe_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pe_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pe_quality = 'L';
+      else
+         kkt->pe_quality = '?';
+      _glp_check_kkt(lp, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max,
+         &re_ind);
+      kkt->pb_ae_max = ae_max;
+      kkt->pb_ae_ind = ae_ind;
+      kkt->pb_re_max = re_max;
+      kkt->pb_re_ind = re_ind;
+      if (re_max <= 1e-9)
+         kkt->pb_quality = 'H';
+      else if (re_max <= 1e-6)
+         kkt->pb_quality = 'M';
+      else if (re_max <= 1e-3)
+         kkt->pb_quality = 'L';
+      else
+         kkt->pb_quality = '?';
+      return;
+}
+
+#if 1 /* 17/XI-2009 */
+static void reset_parms(LPX *lp)
+{     /* reset control parameters to default values */
+      struct LPXCPS *cps = lp->parms;
+      xassert(cps != NULL);
+      cps->msg_lev  = 3;
+      cps->scale    = 1;
+      cps->dual     = 0;
+      cps->price    = 1;
+      cps->relax    = 0.07;
+      cps->tol_bnd  = 1e-7;
+      cps->tol_dj   = 1e-7;
+      cps->tol_piv  = 1e-9;
+      cps->round    = 0;
+      cps->obj_ll   = -DBL_MAX;
+      cps->obj_ul   = +DBL_MAX;
+      cps->it_lim   = -1;
+#if 0 /* 02/XII-2010 */
+      lp->it_cnt   = 0;
+#endif
+      cps->tm_lim   = -1.0;
+      cps->out_frq  = 200;
+      cps->out_dly  = 0.0;
+      cps->branch   = 2;
+      cps->btrack   = 3;
+      cps->tol_int  = 1e-5;
+      cps->tol_obj  = 1e-7;
+      cps->mps_info = 1;
+      cps->mps_obj  = 2;
+      cps->mps_orig = 0;
+      cps->mps_wide = 1;
+      cps->mps_free = 0;
+      cps->mps_skip = 0;
+      cps->lpt_orig = 0;
+      cps->presol = 0;
+      cps->binarize = 0;
+      cps->use_cuts = 0;
+      cps->mip_gap = 0.0;
+      return;
+}
+#endif
+
+#if 1 /* 17/XI-2009 */
+static struct LPXCPS *access_parms(LPX *lp)
+{     /* allocate and initialize control parameters, if necessary */
+      if (lp->parms == NULL)
+      {  lp->parms = xmalloc(sizeof(struct LPXCPS));
+         reset_parms(lp);
+      }
+      return lp->parms;
+}
+#endif
+
+#if 1 /* 17/XI-2009 */
+void lpx_reset_parms(LPX *lp)
+{     /* reset control parameters to default values */
+      access_parms(lp);
+      reset_parms(lp);
+      return;
+}
+#endif
+
+void lpx_set_int_parm(LPX *lp, int parm, int val)
+{     /* set (change) integer control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      switch (parm)
+      {  case LPX_K_MSGLEV:
+            if (!(0 <= val && val <= 3))
+               xerror("lpx_set_int_parm: MSGLEV = %d; invalid value\n",
+                  val);
+            cps->msg_lev = val;
+            break;
+         case LPX_K_SCALE:
+            if (!(0 <= val && val <= 3))
+               xerror("lpx_set_int_parm: SCALE = %d; invalid value\n",
+                  val);
+            cps->scale = val;
+            break;
+         case LPX_K_DUAL:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: DUAL = %d; invalid value\n",
+                  val);
+            cps->dual = val;
+            break;
+         case LPX_K_PRICE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: PRICE = %d; invalid value\n",
+                  val);
+            cps->price = val;
+            break;
+         case LPX_K_ROUND:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: ROUND = %d; invalid value\n",
+                  val);
+            cps->round = val;
+            break;
+         case LPX_K_ITLIM:
+            cps->it_lim = val;
+            break;
+         case LPX_K_ITCNT:
+            lp->it_cnt = val;
+            break;
+         case LPX_K_OUTFRQ:
+            if (!(val > 0))
+               xerror("lpx_set_int_parm: OUTFRQ = %d; invalid value\n",
+                  val);
+            cps->out_frq = val;
+            break;
+         case LPX_K_BRANCH:
+            if (!(val == 0 || val == 1 || val == 2 || val == 3))
+               xerror("lpx_set_int_parm: BRANCH = %d; invalid value\n",
+                  val);
+            cps->branch = val;
+            break;
+         case LPX_K_BTRACK:
+            if (!(val == 0 || val == 1 || val == 2 || val == 3))
+               xerror("lpx_set_int_parm: BTRACK = %d; invalid value\n",
+                  val);
+            cps->btrack = val;
+            break;
+         case LPX_K_MPSINFO:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSINFO = %d; invalid value\n",
+                  val);
+            cps->mps_info = val;
+            break;
+         case LPX_K_MPSOBJ:
+            if (!(val == 0 || val == 1 || val == 2))
+               xerror("lpx_set_int_parm: MPSOBJ = %d; invalid value\n",
+                  val);
+            cps->mps_obj = val;
+            break;
+         case LPX_K_MPSORIG:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSORIG = %d; invalid value\n",
+                  val);
+            cps->mps_orig = val;
+            break;
+         case LPX_K_MPSWIDE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSWIDE = %d; invalid value\n",
+                  val);
+            cps->mps_wide = val;
+            break;
+         case LPX_K_MPSFREE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSFREE = %d; invalid value\n",
+                  val);
+            cps->mps_free = val;
+            break;
+         case LPX_K_MPSSKIP:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: MPSSKIP = %d; invalid value\n",
+                  val);
+            cps->mps_skip = val;
+            break;
+         case LPX_K_LPTORIG:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: LPTORIG = %d; invalid value\n",
+                  val);
+            cps->lpt_orig = val;
+            break;
+         case LPX_K_PRESOL:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: PRESOL = %d; invalid value\n",
+                  val);
+            cps->presol = val;
+            break;
+         case LPX_K_BINARIZE:
+            if (!(val == 0 || val == 1))
+               xerror("lpx_set_int_parm: BINARIZE = %d; invalid value\n"
+                  , val);
+            cps->binarize = val;
+            break;
+         case LPX_K_USECUTS:
+            if (val & ~LPX_C_ALL)
+            xerror("lpx_set_int_parm: USECUTS = 0x%X; invalid value\n",
+                  val);
+            cps->use_cuts = val;
+            break;
+         case LPX_K_BFTYPE:
+#if 0
+            if (!(1 <= val && val <= 3))
+               xerror("lpx_set_int_parm: BFTYPE = %d; invalid value\n",
+                  val);
+            cps->bf_type = val;
+#else
+            {  glp_bfcp parm;
+               glp_get_bfcp(lp, &parm);
+               switch (val)
+               {  case 1:
+                     parm.type = GLP_BF_FT; break;
+                  case 2:
+                     parm.type = GLP_BF_BG; break;
+                  case 3:
+                     parm.type = GLP_BF_GR; break;
+                  default:
+                     xerror("lpx_set_int_parm: BFTYPE = %d; invalid val"
+                        "ue\n", val);
+               }
+               glp_set_bfcp(lp, &parm);
+            }
+#endif
+            break;
+         default:
+            xerror("lpx_set_int_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return;
+}
+
+int lpx_get_int_parm(LPX *lp, int parm)
+{     /* query integer control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      int val = 0;
+      switch (parm)
+      {  case LPX_K_MSGLEV:
+            val = cps->msg_lev; break;
+         case LPX_K_SCALE:
+            val = cps->scale; break;
+         case LPX_K_DUAL:
+            val = cps->dual; break;
+         case LPX_K_PRICE:
+            val = cps->price; break;
+         case LPX_K_ROUND:
+            val = cps->round; break;
+         case LPX_K_ITLIM:
+            val = cps->it_lim; break;
+         case LPX_K_ITCNT:
+            val = lp->it_cnt; break;
+         case LPX_K_OUTFRQ:
+            val = cps->out_frq; break;
+         case LPX_K_BRANCH:
+            val = cps->branch; break;
+         case LPX_K_BTRACK:
+            val = cps->btrack; break;
+         case LPX_K_MPSINFO:
+            val = cps->mps_info; break;
+         case LPX_K_MPSOBJ:
+            val = cps->mps_obj; break;
+         case LPX_K_MPSORIG:
+            val = cps->mps_orig; break;
+         case LPX_K_MPSWIDE:
+            val = cps->mps_wide; break;
+         case LPX_K_MPSFREE:
+            val = cps->mps_free; break;
+         case LPX_K_MPSSKIP:
+            val = cps->mps_skip; break;
+         case LPX_K_LPTORIG:
+            val = cps->lpt_orig; break;
+         case LPX_K_PRESOL:
+            val = cps->presol; break;
+         case LPX_K_BINARIZE:
+            val = cps->binarize; break;
+         case LPX_K_USECUTS:
+            val = cps->use_cuts; break;
+         case LPX_K_BFTYPE:
+#if 0
+            val = cps->bf_type; break;
+#else
+            {  glp_bfcp parm;
+               glp_get_bfcp(lp, &parm);
+               switch (parm.type)
+               {  case GLP_BF_FT:
+                     val = 1; break;
+                  case GLP_BF_BG:
+                     val = 2; break;
+                  case GLP_BF_GR:
+                     val = 3; break;
+                  default:
+                     xassert(lp != lp);
+               }
+            }
+            break;
+#endif
+         default:
+            xerror("lpx_get_int_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return val;
+}
+
+void lpx_set_real_parm(LPX *lp, int parm, double val)
+{     /* set (change) real control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      switch (parm)
+      {  case LPX_K_RELAX:
+            if (!(0.0 <= val && val <= 1.0))
+               xerror("lpx_set_real_parm: RELAX = %g; invalid value\n",
+                  val);
+            cps->relax = val;
+            break;
+         case LPX_K_TOLBND:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLBND = %g; invalid value\n",
+                  val);
+#if 0
+            if (cps->tol_bnd > val)
+            {  /* invalidate the basic solution */
+               lp->p_stat = LPX_P_UNDEF;
+               lp->d_stat = LPX_D_UNDEF;
+            }
+#endif
+            cps->tol_bnd = val;
+            break;
+         case LPX_K_TOLDJ:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLDJ = %g; invalid value\n",
+                  val);
+#if 0
+            if (cps->tol_dj > val)
+            {  /* invalidate the basic solution */
+               lp->p_stat = LPX_P_UNDEF;
+               lp->d_stat = LPX_D_UNDEF;
+            }
+#endif
+            cps->tol_dj = val;
+            break;
+         case LPX_K_TOLPIV:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLPIV = %g; invalid value\n",
+                  val);
+            cps->tol_piv = val;
+            break;
+         case LPX_K_OBJLL:
+            cps->obj_ll = val;
+            break;
+         case LPX_K_OBJUL:
+            cps->obj_ul = val;
+            break;
+         case LPX_K_TMLIM:
+            cps->tm_lim = val;
+            break;
+         case LPX_K_OUTDLY:
+            cps->out_dly = val;
+            break;
+         case LPX_K_TOLINT:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLINT = %g; invalid value\n",
+                  val);
+            cps->tol_int = val;
+            break;
+         case LPX_K_TOLOBJ:
+            if (!(DBL_EPSILON <= val && val <= 0.001))
+               xerror("lpx_set_real_parm: TOLOBJ = %g; invalid value\n",
+                  val);
+            cps->tol_obj = val;
+            break;
+         case LPX_K_MIPGAP:
+            if (val < 0.0)
+               xerror("lpx_set_real_parm: MIPGAP = %g; invalid value\n",
+                  val);
+            cps->mip_gap = val;
+            break;
+         default:
+            xerror("lpx_set_real_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return;
+}
+
+double lpx_get_real_parm(LPX *lp, int parm)
+{     /* query real control parameter */
+#if 0 /* 17/XI-2009 */
+      struct LPXCPS *cps = lp->cps;
+#else
+      struct LPXCPS *cps = access_parms(lp);
+#endif
+      double val = 0.0;
+      switch (parm)
+      {  case LPX_K_RELAX:
+            val = cps->relax;
+            break;
+         case LPX_K_TOLBND:
+            val = cps->tol_bnd;
+            break;
+         case LPX_K_TOLDJ:
+            val = cps->tol_dj;
+            break;
+         case LPX_K_TOLPIV:
+            val = cps->tol_piv;
+            break;
+         case LPX_K_OBJLL:
+            val = cps->obj_ll;
+            break;
+         case LPX_K_OBJUL:
+            val = cps->obj_ul;
+            break;
+         case LPX_K_TMLIM:
+            val = cps->tm_lim;
+            break;
+         case LPX_K_OUTDLY:
+            val = cps->out_dly;
+            break;
+         case LPX_K_TOLINT:
+            val = cps->tol_int;
+            break;
+         case LPX_K_TOLOBJ:
+            val = cps->tol_obj;
+            break;
+         case LPX_K_MIPGAP:
+            val = cps->mip_gap;
+            break;
+         default:
+            xerror("lpx_get_real_parm: parm = %d; invalid parameter\n",
+               parm);
+      }
+      return val;
+}
+
+LPX *lpx_read_mps(const char *fname)
+{     /* read problem data in fixed MPS format */
+      LPX *lp = lpx_create_prob();
+      if (glp_read_mps(lp, GLP_MPS_DECK, NULL, fname))
+         lpx_delete_prob(lp), lp = NULL;
+      return lp;
+}
+
+int lpx_write_mps(LPX *lp, const char *fname)
+{     /* write problem data in fixed MPS format */
+      return glp_write_mps(lp, GLP_MPS_DECK, NULL, fname);
+}
+
+int lpx_read_bas(LPX *lp, const char *fname)
+{     /* read LP basis in fixed MPS format */
+#if 0 /* 13/IV-2009 */
+      return read_bas(lp, fname);
+#else
+      xassert(lp == lp);
+      xassert(fname == fname);
+      xerror("lpx_read_bas: operation not supported\n");
+      return 0;
+#endif
+}
+
+int lpx_write_bas(LPX *lp, const char *fname)
+{     /* write LP basis in fixed MPS format */
+#if 0 /* 13/IV-2009 */
+      return write_bas(lp, fname);
+#else
+      xassert(lp == lp);
+      xassert(fname == fname);
+      xerror("lpx_write_bas: operation not supported\n");
+      return 0;
+#endif
+}
+
+LPX *lpx_read_freemps(const char *fname)
+{     /* read problem data in free MPS format */
+      LPX *lp = lpx_create_prob();
+      if (glp_read_mps(lp, GLP_MPS_FILE, NULL, fname))
+         lpx_delete_prob(lp), lp = NULL;
+      return lp;
+}
+
+int lpx_write_freemps(LPX *lp, const char *fname)
+{     /* write problem data in free MPS format */
+      return glp_write_mps(lp, GLP_MPS_FILE, NULL, fname);
+}
+
+LPX *lpx_read_cpxlp(const char *fname)
+{     /* read problem data in CPLEX LP format */
+      LPX *lp;
+      lp = lpx_create_prob();
+      if (glp_read_lp(lp, NULL, fname))
+         lpx_delete_prob(lp), lp = NULL;
+      return lp;
+}
+
+int lpx_write_cpxlp(LPX *lp, const char *fname)
+{     /* write problem data in CPLEX LP format */
+      return glp_write_lp(lp, NULL, fname);
+}
+
+LPX *lpx_read_model(const char *model, const char *data, const char
+      *output)
+{     /* read LP/MIP model written in GNU MathProg language */
+      LPX *lp = NULL;
+      glp_tran *tran;
+      /* allocate the translator workspace */
+      tran = glp_mpl_alloc_wksp();
+      /* read model section and optional data section */
+      if (glp_mpl_read_model(tran, model, data != NULL)) goto done;
+      /* read separate data section, if required */
+      if (data != NULL)
+         if (glp_mpl_read_data(tran, data)) goto done;
+      /* generate the model */
+      if (glp_mpl_generate(tran, output)) goto done;
+      /* build the problem instance from the model */
+      lp = glp_create_prob();
+      glp_mpl_build_prob(tran, lp);
+done: /* free the translator workspace */
+      glp_mpl_free_wksp(tran);
+      /* bring the problem object to the calling program */
+      return lp;
+}
+
+int lpx_print_prob(LPX *lp, const char *fname)
+{     /* write problem data in plain text format */
+      return glp_write_lp(lp, NULL, fname);
+}
+
+int lpx_print_sol(LPX *lp, const char *fname)
+{     /* write LP problem solution in printable format */
+      return glp_print_sol(lp, fname);
+}
+
+int lpx_print_sens_bnds(LPX *lp, const char *fname)
+{     /* write bounds sensitivity information */
+      if (glp_get_status(lp) == GLP_OPT && !glp_bf_exists(lp))
+         glp_factorize(lp);
+      return glp_print_ranges(lp, 0, NULL, 0, fname);
+}
+
+int lpx_print_ips(LPX *lp, const char *fname)
+{     /* write interior point solution in printable format */
+      return glp_print_ipt(lp, fname);
+}
+
+int lpx_print_mip(LPX *lp, const char *fname)
+{     /* write MIP problem solution in printable format */
+      return glp_print_mip(lp, fname);
+}
+
+int lpx_is_b_avail(glp_prob *lp)
+{     /* check if LP basis is available */
+      return glp_bf_exists(lp);
+}
+
+int lpx_main(int argc, const char *argv[])
+{     /* stand-alone LP/MIP solver */
+      return glp_main(argc, argv);
+}
+
+/* eof */
Index: deps/glpk/src/glplpx02.c
===================================================================
--- deps/glpk/src/glplpx02.c	(revision 9)
+++ deps/glpk/src/glplpx02.c	(revision 9)
@@ -0,0 +1,264 @@
+/* glplpx02.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  lpx_put_solution - store basic solution components
+*
+*  SYNOPSIS
+*
+*  void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
+*     const int *d_stat, const double *obj_val, const int r_stat[],
+*     const double r_prim[], const double r_dual[], const int c_stat[],
+*     const double c_prim[], const double c_dual[])
+*
+*  DESCRIPTION
+*
+*  The routine lpx_put_solution stores basic solution components to the
+*  specified problem object.
+*
+*  The parameter inval is the basis factorization invalidity flag.
+*  If this flag is clear, the current status of the basis factorization
+*  remains unchanged. If this flag is set, the routine invalidates the
+*  basis factorization.
+*
+*  The parameter p_stat is a pointer to the status of primal basic
+*  solution, which should be specified as follows:
+*
+*  GLP_UNDEF  - primal solution is undefined;
+*  GLP_FEAS   - primal solution is feasible;
+*  GLP_INFEAS - primal solution is infeasible;
+*  GLP_NOFEAS - no primal feasible solution exists.
+*
+*  If the parameter p_stat is NULL, the current status of primal basic
+*  solution remains unchanged.
+*
+*  The parameter d_stat is a pointer to the status of dual basic
+*  solution, which should be specified as follows:
+*
+*  GLP_UNDEF  - dual solution is undefined;
+*  GLP_FEAS   - dual solution is feasible;
+*  GLP_INFEAS - dual solution is infeasible;
+*  GLP_NOFEAS - no dual feasible solution exists.
+*
+*  If the parameter d_stat is NULL, the current status of dual basic
+*  solution remains unchanged.
+*
+*  The parameter obj_val is a pointer to the objective function value.
+*  If it is NULL, the current value of the objective function remains
+*  unchanged.
+*
+*  The array element r_stat[i], 1 <= i <= m (where m is the number of
+*  rows in the problem object), specifies the status of i-th auxiliary
+*  variable, which should be specified as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on lower bound;
+*  GLP_NU - non-basic variable on upper bound;
+*  GLP_NF - non-basic free variable;
+*  GLP_NS - non-basic fixed variable.
+*
+*  If the parameter r_stat is NULL, the current statuses of auxiliary
+*  variables remain unchanged.
+*
+*  The array element r_prim[i], 1 <= i <= m (where m is the number of
+*  rows in the problem object), specifies a primal value of i-th
+*  auxiliary variable. If the parameter r_prim is NULL, the current
+*  primal values of auxiliary variables remain unchanged.
+*
+*  The array element r_dual[i], 1 <= i <= m (where m is the number of
+*  rows in the problem object), specifies a dual value (reduced cost)
+*  of i-th auxiliary variable. If the parameter r_dual is NULL, the
+*  current dual values of auxiliary variables remain unchanged.
+*
+*  The array element c_stat[j], 1 <= j <= n (where n is the number of
+*  columns in the problem object), specifies the status of j-th
+*  structural variable, which should be specified as follows:
+*
+*  GLP_BS - basic variable;
+*  GLP_NL - non-basic variable on lower bound;
+*  GLP_NU - non-basic variable on upper bound;
+*  GLP_NF - non-basic free variable;
+*  GLP_NS - non-basic fixed variable.
+*
+*  If the parameter c_stat is NULL, the current statuses of structural
+*  variables remain unchanged.
+*
+*  The array element c_prim[j], 1 <= j <= n (where n is the number of
+*  columns in the problem object), specifies a primal value of j-th
+*  structural variable. If the parameter c_prim is NULL, the current
+*  primal values of structural variables remain unchanged.
+*
+*  The array element c_dual[j], 1 <= j <= n (where n is the number of
+*  columns in the problem object), specifies a dual value (reduced cost)
+*  of j-th structural variable. If the parameter c_dual is NULL, the
+*  current dual values of structural variables remain unchanged. */
+
+void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat,
+      const int *d_stat, const double *obj_val, const int r_stat[],
+      const double r_prim[], const double r_dual[], const int c_stat[],
+      const double c_prim[], const double c_dual[])
+{     GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      /* invalidate the basis factorization, if required */
+      if (inval) lp->valid = 0;
+      /* store primal status */
+      if (p_stat != NULL)
+      {  if (!(*p_stat == GLP_UNDEF  || *p_stat == GLP_FEAS ||
+               *p_stat == GLP_INFEAS || *p_stat == GLP_NOFEAS))
+            xerror("lpx_put_solution: p_stat = %d; invalid primal statu"
+               "s\n", *p_stat);
+         lp->pbs_stat = *p_stat;
+      }
+      /* store dual status */
+      if (d_stat != NULL)
+      {  if (!(*d_stat == GLP_UNDEF  || *d_stat == GLP_FEAS ||
+               *d_stat == GLP_INFEAS || *d_stat == GLP_NOFEAS))
+            xerror("lpx_put_solution: d_stat = %d; invalid dual status "
+               "\n", *d_stat);
+         lp->dbs_stat = *d_stat;
+      }
+      /* store objective function value */
+      if (obj_val != NULL) lp->obj_val = *obj_val;
+      /* store row solution components */
+      for (i = 1; i <= lp->m; i++)
+      {  row = lp->row[i];
+         if (r_stat != NULL)
+         {  if (!(r_stat[i] == GLP_BS ||
+                  row->type == GLP_FR && r_stat[i] == GLP_NF ||
+                  row->type == GLP_LO && r_stat[i] == GLP_NL ||
+                  row->type == GLP_UP && r_stat[i] == GLP_NU ||
+                  row->type == GLP_DB && r_stat[i] == GLP_NL ||
+                  row->type == GLP_DB && r_stat[i] == GLP_NU ||
+                  row->type == GLP_FX && r_stat[i] == GLP_NS))
+               xerror("lpx_put_solution: r_stat[%d] = %d; invalid row s"
+                  "tatus\n", i, r_stat[i]);
+            row->stat = r_stat[i];
+         }
+         if (r_prim != NULL) row->prim = r_prim[i];
+         if (r_dual != NULL) row->dual = r_dual[i];
+      }
+      /* store column solution components */
+      for (j = 1; j <= lp->n; j++)
+      {  col = lp->col[j];
+         if (c_stat != NULL)
+         {  if (!(c_stat[j] == GLP_BS ||
+                  col->type == GLP_FR && c_stat[j] == GLP_NF ||
+                  col->type == GLP_LO && c_stat[j] == GLP_NL ||
+                  col->type == GLP_UP && c_stat[j] == GLP_NU ||
+                  col->type == GLP_DB && c_stat[j] == GLP_NL ||
+                  col->type == GLP_DB && c_stat[j] == GLP_NU ||
+                  col->type == GLP_FX && c_stat[j] == GLP_NS))
+               xerror("lpx_put_solution: c_stat[%d] = %d; invalid colum"
+                  "n status\n", j, c_stat[j]);
+            col->stat = c_stat[j];
+         }
+         if (c_prim != NULL) col->prim = c_prim[j];
+         if (c_dual != NULL) col->dual = c_dual[j];
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- lpx_put_mip_soln - store mixed integer solution components.
+--
+-- *Synopsis*
+--
+-- #include "glplpx.h"
+-- void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
+--    double col_mipx[]);
+--
+-- *Description*
+--
+-- The routine lpx_put_mip_soln stores solution components obtained by
+-- branch-and-bound solver into the specified problem object.
+--
+-- NOTE: This routine is intended for internal use only. */
+
+void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[],
+      double col_mipx[])
+{     GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      double sum;
+      /* store mixed integer status */
+#if 0
+      if (!(i_stat == LPX_I_UNDEF || i_stat == LPX_I_OPT ||
+            i_stat == LPX_I_FEAS  || i_stat == LPX_I_NOFEAS))
+         fault("lpx_put_mip_soln: i_stat = %d; invalid mixed integer st"
+            "atus", i_stat);
+      lp->i_stat = i_stat;
+#else
+      switch (i_stat)
+      {  case LPX_I_UNDEF:
+            lp->mip_stat = GLP_UNDEF; break;
+         case LPX_I_OPT:
+            lp->mip_stat = GLP_OPT;  break;
+         case LPX_I_FEAS:
+            lp->mip_stat = GLP_FEAS; break;
+         case LPX_I_NOFEAS:
+            lp->mip_stat = GLP_NOFEAS; break;
+         default:
+            xerror("lpx_put_mip_soln: i_stat = %d; invalid mixed intege"
+               "r status\n", i_stat);
+      }
+#endif
+      /* store row solution components */
+      if (row_mipx != NULL)
+      {  for (i = 1; i <= lp->m; i++)
+         {  row = lp->row[i];
+            row->mipx = row_mipx[i];
+         }
+      }
+      /* store column solution components */
+      if (col_mipx != NULL)
+      {  for (j = 1; j <= lp->n; j++)
+         {  col = lp->col[j];
+            col->mipx = col_mipx[j];
+         }
+      }
+      /* if the solution is claimed to be integer feasible, check it */
+      if (lp->mip_stat == GLP_OPT || lp->mip_stat == GLP_FEAS)
+      {  for (j = 1; j <= lp->n; j++)
+         {  col = lp->col[j];
+            if (col->kind == GLP_IV && col->mipx != floor(col->mipx))
+               xerror("lpx_put_mip_soln: col_mipx[%d] = %.*g; must be i"
+                  "ntegral\n", j, DBL_DIG, col->mipx);
+         }
+      }
+      /* compute the objective function value */
+      sum = lp->c0;
+      for (j = 1; j <= lp->n; j++)
+      {  col = lp->col[j];
+         sum += col->coef * col->mipx;
+      }
+      lp->mip_obj = sum;
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glplpx03.c
===================================================================
--- deps/glpk/src/glplpx03.c	(revision 9)
+++ deps/glpk/src/glplpx03.c	(revision 9)
@@ -0,0 +1,302 @@
+/* glplpx03.c (OPB format) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Author: Oscar Gustafsson <oscarg@isy.liu.se>.
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpapi.h"
+#if 0 /* 24/XII-2009; by mao */
+#include "glpipp.h"
+#endif
+
+/*----------------------------------------------------------------------
+-- lpx_write_pb - write problem data in (normalized) OPB format.
+--
+-- *Synopsis*
+--
+-- #include "glplpx.h"
+-- int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+--    int binarize);
+--
+-- *Description*
+--
+-- The routine lpx_write_pb writes problem data in OPB format
+-- to an output text file whose name is the character string fname.
+-- If normalized is non-zero the output will be generated in a
+-- normalized form with sequentially numbered variables, x1, x2 etc.
+-- If binarize, any integer variable will be repalzec by binary ones,
+-- see ipp_binarize
+--
+-- *Returns*
+--
+-- If the operation was successful, the routine returns zero. Otherwise
+-- the routine prints an error message and returns non-zero. */
+
+#if 1 /* 24/XII-2009; by mao (disabled, because IPP was removed) */
+int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+      int binarize)
+{     xassert(lp == lp);
+      xassert(fname == fname);
+      xassert(normalized == normalized);
+      xassert(binarize == binarize);
+      xprintf("lpx_write_pb: sorry, currently this operation is not ava"
+         "ilable\n");
+      return 1;
+}
+#else
+int lpx_write_pb(LPX *lp, const char *fname, int normalized,
+      int binarize)
+{
+  FILE* fp;
+  int m,n,i,j,k,o,nonfree=0, obj_dir, dbl, *ndx, row_type, emptylhs=0;
+  double coeff, *val, bound, constant/*=0.0*/;
+  char* objconstname = "dummy_one";
+  char* emptylhsname = "dummy_zero";
+
+  /* Variables needed for possible binarization */
+  /*LPX* tlp;*/
+  IPP *ipp = NULL;
+  /*tlp=lp;*/
+
+  if(binarize) /* Transform integer variables to binary ones */
+    {
+      ipp = ipp_create_wksp();
+      ipp_load_orig(ipp, lp);
+      ipp_binarize(ipp);
+      lp = ipp_build_prob(ipp);
+    }
+  fp = fopen(fname, "w");
+
+  if(fp!= NULL)
+    {
+      xprintf(
+          "lpx_write_pb: writing problem in %sOPB format to `%s'...\n",
+              (normalized?"normalized ":""), fname);
+
+      m = glp_get_num_rows(lp);
+      n = glp_get_num_cols(lp);
+      for(i=1;i<=m;i++)
+        {
+          switch(glp_get_row_type(lp,i))
+            {
+            case GLP_LO:
+            case GLP_UP:
+            case GLP_FX:
+              {
+                nonfree += 1;
+                break;
+              }
+            case GLP_DB:
+              {
+                nonfree += 2;
+                break;
+              }
+            }
+        }
+      constant=glp_get_obj_coef(lp,0);
+      fprintf(fp,"* #variables = %d #constraints = %d\n",
+         n + (constant == 0?1:0), nonfree + (constant == 0?1:0));
+      /* Objective function */
+      obj_dir = glp_get_obj_dir(lp);
+      fprintf(fp,"min: ");
+      for(i=1;i<=n;i++)
+        {
+          coeff = glp_get_obj_coef(lp,i);
+          if(coeff != 0.0)
+            {
+              if(obj_dir == GLP_MAX)
+                coeff=-coeff;
+              if(normalized)
+                fprintf(fp, " %d x%d", (int)coeff, i);
+              else
+                fprintf(fp, " %d*%s", (int)coeff,
+                  glp_get_col_name(lp,i));
+
+            }
+        }
+      if(constant)
+        {
+          if(normalized)
+            fprintf(fp, " %d x%d", (int)constant, n+1);
+          else
+            fprintf(fp, " %d*%s", (int)constant, objconstname);
+        }
+      fprintf(fp,";\n");
+
+      if(normalized && !binarize)  /* Name substitution */
+        {
+          fprintf(fp,"* Variable name substitution:\n");
+          for(j=1;j<=n;j++)
+            {
+              fprintf(fp, "* x%d = %s\n", j, glp_get_col_name(lp,j));
+            }
+          if(constant)
+            fprintf(fp, "* x%d = %s\n", n+1, objconstname);
+        }
+
+      ndx = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(double));
+
+      /* Constraints */
+      for(j=1;j<=m;j++)
+        {
+          row_type=glp_get_row_type(lp,j);
+          if(row_type!=GLP_FR)
+            {
+              if(row_type == GLP_DB)
+                {
+                  dbl=2;
+                  row_type = GLP_UP;
+                }
+              else
+                {
+                  dbl=1;
+                }
+              k=glp_get_mat_row(lp, j, ndx, val);
+              for(o=1;o<=dbl;o++)
+                {
+                  if(o==2)
+                    {
+                      row_type = GLP_LO;
+                    }
+                  if(k==0) /* Empty LHS */
+                    {
+                      emptylhs = 1;
+                      if(normalized)
+                        {
+                          fprintf(fp, "0 x%d ", n+2);
+                        }
+                      else
+                        {
+                          fprintf(fp, "0*%s ", emptylhsname);
+                        }
+                    }
+
+                  for(i=1;i<=k;i++)
+                    {
+                      if(val[i] != 0.0)
+                        {
+
+                          if(normalized)
+                            {
+                              fprintf(fp, "%d x%d ",
+              (row_type==GLP_UP)?(-(int)val[i]):((int)val[i]), ndx[i]);
+                            }
+                          else
+                            {
+                              fprintf(fp, "%d*%s ", (int)val[i],
+                                      glp_get_col_name(lp,ndx[i]));
+                            }
+                        }
+                    }
+                  switch(row_type)
+                    {
+                    case GLP_LO:
+                      {
+                        fprintf(fp, ">=");
+                        bound = glp_get_row_lb(lp,j);
+                        break;
+                      }
+                    case GLP_UP:
+                      {
+                        if(normalized)
+                          {
+                            fprintf(fp, ">=");
+                            bound = -glp_get_row_ub(lp,j);
+                          }
+                        else
+                          {
+                            fprintf(fp, "<=");
+                            bound = glp_get_row_ub(lp,j);
+                          }
+
+                        break;
+                      }
+                    case GLP_FX:
+                      {
+                        fprintf(fp, "=");
+                        bound = glp_get_row_lb(lp,j);
+                        break;
+                      }
+                    }
+                  fprintf(fp," %d;\n",(int)bound);
+                }
+            }
+        }
+      xfree(ndx);
+      xfree(val);
+
+      if(constant)
+        {
+          xprintf(
+        "lpx_write_pb: adding constant objective function variable\n");
+
+          if(normalized)
+            fprintf(fp, "1 x%d = 1;\n", n+1);
+          else
+            fprintf(fp, "1*%s = 1;\n", objconstname);
+        }
+      if(emptylhs)
+        {
+          xprintf(
+            "lpx_write_pb: adding dummy variable for empty left-hand si"
+            "de constraint\n");
+
+          if(normalized)
+            fprintf(fp, "1 x%d = 0;\n", n+2);
+          else
+            fprintf(fp, "1*%s = 0;\n", emptylhsname);
+        }
+
+    }
+  else
+    {
+      xprintf("Problems opening file for writing: %s\n", fname);
+      return(1);
+    }
+  fflush(fp);
+  if (ferror(fp))
+    {  xprintf("lpx_write_pb: can't write to `%s' - %s\n", fname,
+               strerror(errno));
+    goto fail;
+    }
+  fclose(fp);
+
+
+  if(binarize)
+    {
+      /* delete the resultant problem object */
+      if (lp != NULL) lpx_delete_prob(lp);
+      /* delete MIP presolver workspace */
+      if (ipp != NULL) ipp_delete_wksp(ipp);
+      /*lp=tlp;*/
+    }
+  return 0;
+ fail: if (fp != NULL) fclose(fp);
+  return 1;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpluf.c
===================================================================
--- deps/glpk/src/glpluf.c	(revision 9)
+++ deps/glpk/src/glpluf.c	(revision 9)
@@ -0,0 +1,1846 @@
+/* glpluf.c (LU-factorization) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpluf.h"
+#define xfault xerror
+
+/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
+
+#define N_MAX 100000000 /* = 100*10^6 */
+/* maximal order of the original matrix */
+
+/***********************************************************************
+*  NAME
+*
+*  luf_create_it - create LU-factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  LUF *luf_create_it(void);
+*
+*  DESCRIPTION
+*
+*  The routine luf_create_it creates a program object, which represents
+*  LU-factorization of a square matrix.
+*
+*  RETURNS
+*
+*  The routine luf_create_it returns a pointer to the object created. */
+
+LUF *luf_create_it(void)
+{     LUF *luf;
+      luf = xmalloc(sizeof(LUF));
+      luf->n_max = luf->n = 0;
+      luf->valid = 0;
+      luf->fr_ptr = luf->fr_len = NULL;
+      luf->fc_ptr = luf->fc_len = NULL;
+      luf->vr_ptr = luf->vr_len = luf->vr_cap = NULL;
+      luf->vr_piv = NULL;
+      luf->vc_ptr = luf->vc_len = luf->vc_cap = NULL;
+      luf->pp_row = luf->pp_col = NULL;
+      luf->qq_row = luf->qq_col = NULL;
+      luf->sv_size = 0;
+      luf->sv_beg = luf->sv_end = 0;
+      luf->sv_ind = NULL;
+      luf->sv_val = NULL;
+      luf->sv_head = luf->sv_tail = 0;
+      luf->sv_prev = luf->sv_next = NULL;
+      luf->vr_max = NULL;
+      luf->rs_head = luf->rs_prev = luf->rs_next = NULL;
+      luf->cs_head = luf->cs_prev = luf->cs_next = NULL;
+      luf->flag = NULL;
+      luf->work = NULL;
+      luf->new_sva = 0;
+      luf->piv_tol = 0.10;
+      luf->piv_lim = 4;
+      luf->suhl = 1;
+      luf->eps_tol = 1e-15;
+      luf->max_gro = 1e+10;
+      luf->nnz_a = luf->nnz_f = luf->nnz_v = 0;
+      luf->max_a = luf->big_v = 0.0;
+      luf->rank = 0;
+      return luf;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_defrag_sva - defragment the sparse vector area
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_defrag_sva(LUF *luf);
+*
+*  DESCRIPTION
+*
+*  The routine luf_defrag_sva defragments the sparse vector area (SVA)
+*  gathering all unused locations in one continuous extent. In order to
+*  do that the routine moves all unused locations from the left part of
+*  SVA (which contains rows and columns of the matrix V) to the middle
+*  part (which contains free locations). This is attained by relocating
+*  elements of rows and columns of the matrix V toward the beginning of
+*  the left part.
+*
+*  NOTE that this "garbage collection" involves changing row and column
+*  pointers of the matrix V. */
+
+void luf_defrag_sva(LUF *luf)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_next = luf->sv_next;
+      int sv_beg = 1;
+      int i, j, k;
+      /* skip rows and columns, which do not need to be relocated */
+      for (k = luf->sv_head; k != 0; k = sv_next[k])
+      {  if (k <= n)
+         {  /* i-th row of the matrix V */
+            i = k;
+            if (vr_ptr[i] != sv_beg) break;
+            vr_cap[i] = vr_len[i];
+            sv_beg += vr_cap[i];
+         }
+         else
+         {  /* j-th column of the matrix V */
+            j = k - n;
+            if (vc_ptr[j] != sv_beg) break;
+            vc_cap[j] = vc_len[j];
+            sv_beg += vc_cap[j];
+         }
+      }
+      /* relocate other rows and columns in order to gather all unused
+         locations in one continuous extent */
+      for (k = k; k != 0; k = sv_next[k])
+      {  if (k <= n)
+         {  /* i-th row of the matrix V */
+            i = k;
+            memmove(&sv_ind[sv_beg], &sv_ind[vr_ptr[i]],
+               vr_len[i] * sizeof(int));
+            memmove(&sv_val[sv_beg], &sv_val[vr_ptr[i]],
+               vr_len[i] * sizeof(double));
+            vr_ptr[i] = sv_beg;
+            vr_cap[i] = vr_len[i];
+            sv_beg += vr_cap[i];
+         }
+         else
+         {  /* j-th column of the matrix V */
+            j = k - n;
+            memmove(&sv_ind[sv_beg], &sv_ind[vc_ptr[j]],
+               vc_len[j] * sizeof(int));
+            memmove(&sv_val[sv_beg], &sv_val[vc_ptr[j]],
+               vc_len[j] * sizeof(double));
+            vc_ptr[j] = sv_beg;
+            vc_cap[j] = vc_len[j];
+            sv_beg += vc_cap[j];
+         }
+      }
+      /* set new pointer to the beginning of the free part */
+      luf->sv_beg = sv_beg;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_enlarge_row - enlarge row capacity
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  int luf_enlarge_row(LUF *luf, int i, int cap);
+*
+*  DESCRIPTION
+*
+*  The routine luf_enlarge_row enlarges capacity of the i-th row of the
+*  matrix V to cap locations (assuming that its current capacity is less
+*  than cap). In order to do that the routine relocates elements of the
+*  i-th row to the end of the left part of SVA (which contains rows and
+*  columns of the matrix V) and then expands the left part by allocating
+*  cap free locations from the free part. If there are less than cap
+*  free locations, the routine defragments the sparse vector area.
+*
+*  Due to "garbage collection" this operation may change row and column
+*  pointers of the matrix V.
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+int luf_enlarge_row(LUF *luf, int i, int cap)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      int ret = 0;
+      int cur, k, kk;
+      xassert(1 <= i && i <= n);
+      xassert(vr_cap[i] < cap);
+      /* if there are less than cap free locations, defragment SVA */
+      if (luf->sv_end - luf->sv_beg < cap)
+      {  luf_defrag_sva(luf);
+         if (luf->sv_end - luf->sv_beg < cap)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* save current capacity of the i-th row */
+      cur = vr_cap[i];
+      /* copy existing elements to the beginning of the free part */
+      memmove(&sv_ind[luf->sv_beg], &sv_ind[vr_ptr[i]],
+         vr_len[i] * sizeof(int));
+      memmove(&sv_val[luf->sv_beg], &sv_val[vr_ptr[i]],
+         vr_len[i] * sizeof(double));
+      /* set new pointer and new capacity of the i-th row */
+      vr_ptr[i] = luf->sv_beg;
+      vr_cap[i] = cap;
+      /* set new pointer to the beginning of the free part */
+      luf->sv_beg += cap;
+      /* now the i-th row starts in the rightmost location among other
+         rows and columns of the matrix V, so its node should be moved
+         to the end of the row/column linked list */
+      k = i;
+      /* remove the i-th row node from the linked list */
+      if (sv_prev[k] == 0)
+         luf->sv_head = sv_next[k];
+      else
+      {  /* capacity of the previous row/column can be increased at the
+            expense of old locations of the i-th row */
+         kk = sv_prev[k];
+         if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
+         sv_next[sv_prev[k]] = sv_next[k];
+      }
+      if (sv_next[k] == 0)
+         luf->sv_tail = sv_prev[k];
+      else
+         sv_prev[sv_next[k]] = sv_prev[k];
+      /* insert the i-th row node to the end of the linked list */
+      sv_prev[k] = luf->sv_tail;
+      sv_next[k] = 0;
+      if (sv_prev[k] == 0)
+         luf->sv_head = k;
+      else
+         sv_next[sv_prev[k]] = k;
+      luf->sv_tail = k;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_enlarge_col - enlarge column capacity
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  int luf_enlarge_col(LUF *luf, int j, int cap);
+*
+*  DESCRIPTION
+*
+*  The routine luf_enlarge_col enlarges capacity of the j-th column of
+*  the matrix V to cap locations (assuming that its current capacity is
+*  less than cap). In order to do that the routine relocates elements
+*  of the j-th column to the end of the left part of SVA (which contains
+*  rows and columns of the matrix V) and then expands the left part by
+*  allocating cap free locations from the free part. If there are less
+*  than cap free locations, the routine defragments the sparse vector
+*  area.
+*
+*  Due to "garbage collection" this operation may change row and column
+*  pointers of the matrix V.
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+int luf_enlarge_col(LUF *luf, int j, int cap)
+{     int n = luf->n;
+      int *vr_cap = luf->vr_cap;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      int ret = 0;
+      int cur, k, kk;
+      xassert(1 <= j && j <= n);
+      xassert(vc_cap[j] < cap);
+      /* if there are less than cap free locations, defragment SVA */
+      if (luf->sv_end - luf->sv_beg < cap)
+      {  luf_defrag_sva(luf);
+         if (luf->sv_end - luf->sv_beg < cap)
+         {  ret = 1;
+            goto done;
+         }
+      }
+      /* save current capacity of the j-th column */
+      cur = vc_cap[j];
+      /* copy existing elements to the beginning of the free part */
+      memmove(&sv_ind[luf->sv_beg], &sv_ind[vc_ptr[j]],
+         vc_len[j] * sizeof(int));
+      memmove(&sv_val[luf->sv_beg], &sv_val[vc_ptr[j]],
+         vc_len[j] * sizeof(double));
+      /* set new pointer and new capacity of the j-th column */
+      vc_ptr[j] = luf->sv_beg;
+      vc_cap[j] = cap;
+      /* set new pointer to the beginning of the free part */
+      luf->sv_beg += cap;
+      /* now the j-th column starts in the rightmost location among
+         other rows and columns of the matrix V, so its node should be
+         moved to the end of the row/column linked list */
+      k = n + j;
+      /* remove the j-th column node from the linked list */
+      if (sv_prev[k] == 0)
+         luf->sv_head = sv_next[k];
+      else
+      {  /* capacity of the previous row/column can be increased at the
+            expense of old locations of the j-th column */
+         kk = sv_prev[k];
+         if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
+         sv_next[sv_prev[k]] = sv_next[k];
+      }
+      if (sv_next[k] == 0)
+         luf->sv_tail = sv_prev[k];
+      else
+         sv_prev[sv_next[k]] = sv_prev[k];
+      /* insert the j-th column node to the end of the linked list */
+      sv_prev[k] = luf->sv_tail;
+      sv_next[k] = 0;
+      if (sv_prev[k] == 0)
+         luf->sv_head = k;
+      else
+         sv_next[sv_prev[k]] = k;
+      luf->sv_tail = k;
+done: return ret;
+}
+
+/***********************************************************************
+*  reallocate - reallocate LU-factorization arrays
+*
+*  This routine reallocates arrays, whose size depends of n, the order
+*  of the matrix A to be factorized. */
+
+static void reallocate(LUF *luf, int n)
+{     int n_max = luf->n_max;
+      luf->n = n;
+      if (n <= n_max) goto done;
+      if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
+      if (luf->fr_len != NULL) xfree(luf->fr_len);
+      if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
+      if (luf->fc_len != NULL) xfree(luf->fc_len);
+      if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
+      if (luf->vr_len != NULL) xfree(luf->vr_len);
+      if (luf->vr_cap != NULL) xfree(luf->vr_cap);
+      if (luf->vr_piv != NULL) xfree(luf->vr_piv);
+      if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
+      if (luf->vc_len != NULL) xfree(luf->vc_len);
+      if (luf->vc_cap != NULL) xfree(luf->vc_cap);
+      if (luf->pp_row != NULL) xfree(luf->pp_row);
+      if (luf->pp_col != NULL) xfree(luf->pp_col);
+      if (luf->qq_row != NULL) xfree(luf->qq_row);
+      if (luf->qq_col != NULL) xfree(luf->qq_col);
+      if (luf->sv_prev != NULL) xfree(luf->sv_prev);
+      if (luf->sv_next != NULL) xfree(luf->sv_next);
+      if (luf->vr_max != NULL) xfree(luf->vr_max);
+      if (luf->rs_head != NULL) xfree(luf->rs_head);
+      if (luf->rs_prev != NULL) xfree(luf->rs_prev);
+      if (luf->rs_next != NULL) xfree(luf->rs_next);
+      if (luf->cs_head != NULL) xfree(luf->cs_head);
+      if (luf->cs_prev != NULL) xfree(luf->cs_prev);
+      if (luf->cs_next != NULL) xfree(luf->cs_next);
+      if (luf->flag != NULL) xfree(luf->flag);
+      if (luf->work != NULL) xfree(luf->work);
+      luf->n_max = n_max = n + 100;
+      luf->fr_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->fr_len = xcalloc(1+n_max, sizeof(int));
+      luf->fc_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->fc_len = xcalloc(1+n_max, sizeof(int));
+      luf->vr_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->vr_len = xcalloc(1+n_max, sizeof(int));
+      luf->vr_cap = xcalloc(1+n_max, sizeof(int));
+      luf->vr_piv = xcalloc(1+n_max, sizeof(double));
+      luf->vc_ptr = xcalloc(1+n_max, sizeof(int));
+      luf->vc_len = xcalloc(1+n_max, sizeof(int));
+      luf->vc_cap = xcalloc(1+n_max, sizeof(int));
+      luf->pp_row = xcalloc(1+n_max, sizeof(int));
+      luf->pp_col = xcalloc(1+n_max, sizeof(int));
+      luf->qq_row = xcalloc(1+n_max, sizeof(int));
+      luf->qq_col = xcalloc(1+n_max, sizeof(int));
+      luf->sv_prev = xcalloc(1+n_max+n_max, sizeof(int));
+      luf->sv_next = xcalloc(1+n_max+n_max, sizeof(int));
+      luf->vr_max = xcalloc(1+n_max, sizeof(double));
+      luf->rs_head = xcalloc(1+n_max, sizeof(int));
+      luf->rs_prev = xcalloc(1+n_max, sizeof(int));
+      luf->rs_next = xcalloc(1+n_max, sizeof(int));
+      luf->cs_head = xcalloc(1+n_max, sizeof(int));
+      luf->cs_prev = xcalloc(1+n_max, sizeof(int));
+      luf->cs_next = xcalloc(1+n_max, sizeof(int));
+      luf->flag = xcalloc(1+n_max, sizeof(int));
+      luf->work = xcalloc(1+n_max, sizeof(double));
+done: return;
+}
+
+/***********************************************************************
+*  initialize - initialize LU-factorization data structures
+*
+*  This routine initializes data structures for subsequent computing
+*  the LU-factorization of a given matrix A, which is specified by the
+*  formal routine col. On exit V = A and F = P = Q = I, where I is the
+*  unity matrix. (Row-wise representation of the matrix F is not used
+*  at the factorization stage and therefore is not initialized.)
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int initialize(LUF *luf, int (*col)(void *info, int j, int rn[],
+      double aj[]), void *info)
+{     int n = luf->n;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *pp_row = luf->pp_row;
+      int *pp_col = luf->pp_col;
+      int *qq_row = luf->qq_row;
+      int *qq_col = luf->qq_col;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      double *vr_max = luf->vr_max;
+      int *rs_head = luf->rs_head;
+      int *rs_prev = luf->rs_prev;
+      int *rs_next = luf->rs_next;
+      int *cs_head = luf->cs_head;
+      int *cs_prev = luf->cs_prev;
+      int *cs_next = luf->cs_next;
+      int *flag = luf->flag;
+      double *work = luf->work;
+      int ret = 0;
+      int i, i_ptr, j, j_beg, j_end, k, len, nnz, sv_beg, sv_end, ptr;
+      double big, val;
+      /* free all locations of the sparse vector area */
+      sv_beg = 1;
+      sv_end = luf->sv_size + 1;
+      /* (row-wise representation of the matrix F is not initialized,
+         because it is not used at the factorization stage) */
+      /* build the matrix F in column-wise format (initially F = I) */
+      for (j = 1; j <= n; j++)
+      {  fc_ptr[j] = sv_end;
+         fc_len[j] = 0;
+      }
+      /* clear rows of the matrix V; clear the flag array */
+      for (i = 1; i <= n; i++)
+         vr_len[i] = vr_cap[i] = 0, flag[i] = 0;
+      /* build the matrix V in column-wise format (initially V = A);
+         count non-zeros in rows of this matrix; count total number of
+         non-zeros; compute largest of absolute values of elements */
+      nnz = 0;
+      big = 0.0;
+      for (j = 1; j <= n; j++)
+      {  int *rn = pp_row;
+         double *aj = work;
+         /* obtain j-th column of the matrix A */
+         len = col(info, j, rn, aj);
+         if (!(0 <= len && len <= n))
+            xfault("luf_factorize: j = %d; len = %d; invalid column len"
+               "gth\n", j, len);
+         /* check for free locations */
+         if (sv_end - sv_beg < len)
+         {  /* overflow of the sparse vector area */
+            ret = 1;
+            goto done;
+         }
+         /* set pointer to the j-th column */
+         vc_ptr[j] = sv_beg;
+         /* set length of the j-th column */
+         vc_len[j] = vc_cap[j] = len;
+         /* count total number of non-zeros */
+         nnz += len;
+         /* walk through elements of the j-th column */
+         for (ptr = 1; ptr <= len; ptr++)
+         {  /* get row index and numerical value of a[i,j] */
+            i = rn[ptr];
+            val = aj[ptr];
+            if (!(1 <= i && i <= n))
+               xfault("luf_factorize: i = %d; j = %d; invalid row index"
+                  "\n", i, j);
+            if (flag[i])
+               xfault("luf_factorize: i = %d; j = %d; duplicate element"
+                  " not allowed\n", i, j);
+            if (val == 0.0)
+               xfault("luf_factorize: i = %d; j = %d; zero element not "
+                  "allowed\n", i, j);
+            /* add new element v[i,j] = a[i,j] to j-th column */
+            sv_ind[sv_beg] = i;
+            sv_val[sv_beg] = val;
+            sv_beg++;
+            /* big := max(big, |a[i,j]|) */
+            if (val < 0.0) val = - val;
+            if (big < val) big = val;
+            /* mark non-zero in the i-th position of the j-th column */
+            flag[i] = 1;
+            /* increase length of the i-th row */
+            vr_cap[i]++;
+         }
+         /* reset all non-zero marks */
+         for (ptr = 1; ptr <= len; ptr++) flag[rn[ptr]] = 0;
+      }
+      /* allocate rows of the matrix V */
+      for (i = 1; i <= n; i++)
+      {  /* get length of the i-th row */
+         len = vr_cap[i];
+         /* check for free locations */
+         if (sv_end - sv_beg < len)
+         {  /* overflow of the sparse vector area */
+            ret = 1;
+            goto done;
+         }
+         /* set pointer to the i-th row */
+         vr_ptr[i] = sv_beg;
+         /* reserve locations for the i-th row */
+         sv_beg += len;
+      }
+      /* build the matrix V in row-wise format using representation of
+         this matrix in column-wise format */
+      for (j = 1; j <= n; j++)
+      {  /* walk through elements of the j-th column */
+         j_beg = vc_ptr[j];
+         j_end = j_beg + vc_len[j] - 1;
+         for (k = j_beg; k <= j_end; k++)
+         {  /* get row index and numerical value of v[i,j] */
+            i = sv_ind[k];
+            val = sv_val[k];
+            /* store element in the i-th row */
+            i_ptr = vr_ptr[i] + vr_len[i];
+            sv_ind[i_ptr] = j;
+            sv_val[i_ptr] = val;
+            /* increase count of the i-th row */
+            vr_len[i]++;
+         }
+      }
+      /* initialize the matrices P and Q (initially P = Q = I) */
+      for (k = 1; k <= n; k++)
+         pp_row[k] = pp_col[k] = qq_row[k] = qq_col[k] = k;
+      /* set sva partitioning pointers */
+      luf->sv_beg = sv_beg;
+      luf->sv_end = sv_end;
+      /* the initial physical order of rows and columns of the matrix V
+         is n+1, ..., n+n, 1, ..., n (firstly columns, then rows) */
+      luf->sv_head = n+1;
+      luf->sv_tail = n;
+      for (i = 1; i <= n; i++)
+      {  sv_prev[i] = i-1;
+         sv_next[i] = i+1;
+      }
+      sv_prev[1] = n+n;
+      sv_next[n] = 0;
+      for (j = 1; j <= n; j++)
+      {  sv_prev[n+j] = n+j-1;
+         sv_next[n+j] = n+j+1;
+      }
+      sv_prev[n+1] = 0;
+      sv_next[n+n] = 1;
+      /* clear working arrays */
+      for (k = 1; k <= n; k++)
+      {  flag[k] = 0;
+         work[k] = 0.0;
+      }
+      /* initialize some statistics */
+      luf->nnz_a = nnz;
+      luf->nnz_f = 0;
+      luf->nnz_v = nnz;
+      luf->max_a = big;
+      luf->big_v = big;
+      luf->rank = -1;
+      /* initially the active submatrix is the entire matrix V */
+      /* largest of absolute values of elements in each active row is
+         unknown yet */
+      for (i = 1; i <= n; i++) vr_max[i] = -1.0;
+      /* build linked lists of active rows */
+      for (len = 0; len <= n; len++) rs_head[len] = 0;
+      for (i = 1; i <= n; i++)
+      {  len = vr_len[i];
+         rs_prev[i] = 0;
+         rs_next[i] = rs_head[len];
+         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+         rs_head[len] = i;
+      }
+      /* build linked lists of active columns */
+      for (len = 0; len <= n; len++) cs_head[len] = 0;
+      for (j = 1; j <= n; j++)
+      {  len = vc_len[j];
+         cs_prev[j] = 0;
+         cs_next[j] = cs_head[len];
+         if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
+         cs_head[len] = j;
+      }
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  find_pivot - choose a pivot element
+*
+*  This routine chooses a pivot element in the active submatrix of the
+*  matrix U = P*V*Q.
+*
+*  It is assumed that on entry the matrix U has the following partially
+*  triangularized form:
+* 
+*        1       k         n
+*     1  x x x x x x x x x x
+*        . x x x x x x x x x
+*        . . x x x x x x x x
+*        . . . x x x x x x x
+*     k  . . . . * * * * * *
+*        . . . . * * * * * *
+*        . . . . * * * * * *
+*        . . . . * * * * * *
+*        . . . . * * * * * *
+*     n  . . . . * * * * * *
+* 
+*  where rows and columns k, k+1, ..., n belong to the active submatrix
+*  (elements of the active submatrix are marked by '*').
+*
+*  Since the matrix U = P*V*Q is not stored, the routine works with the
+*  matrix V. It is assumed that the row-wise representation corresponds
+*  to the matrix V, but the column-wise representation corresponds to
+*  the active submatrix of the matrix V, i.e. elements of the matrix V,
+*  which doesn't belong to the active submatrix, are missing from the
+*  column linked lists. It is also assumed that each active row of the
+*  matrix V is in the set R[len], where len is number of non-zeros in
+*  the row, and each active column of the matrix V is in the set C[len],
+*  where len is number of non-zeros in the column (in the latter case
+*  only elements of the active submatrix are counted; such elements are
+*  marked by '*' on the figure above).
+* 
+*  For the reason of numerical stability the routine applies so called
+*  threshold pivoting proposed by J.Reid. It is assumed that an element
+*  v[i,j] can be selected as a pivot candidate if it is not very small
+*  (in absolute value) among other elements in the same row, i.e. if it
+*  satisfies to the stability condition |v[i,j]| >= tol * max|v[i,*]|,
+*  where 0 < tol < 1 is a given tolerance.
+* 
+*  In order to keep sparsity of the matrix V the routine uses Markowitz
+*  strategy, trying to choose such element v[p,q], which satisfies to
+*  the stability condition (see above) and has smallest Markowitz cost
+*  (nr[p]-1) * (nc[q]-1), where nr[p] and nc[q] are numbers of non-zero
+*  elements, respectively, in the p-th row and in the q-th column of the
+*  active submatrix.
+* 
+*  In order to reduce the search, i.e. not to walk through all elements
+*  of the active submatrix, the routine exploits a technique proposed by
+*  I.Duff. This technique is based on using the sets R[len] and C[len]
+*  of active rows and columns.
+* 
+*  If the pivot element v[p,q] has been chosen, the routine stores its
+*  indices to the locations *p and *q and returns zero. Otherwise, if
+*  the active submatrix is empty and therefore the pivot element can't
+*  be chosen, the routine returns non-zero. */
+
+static int find_pivot(LUF *luf, int *_p, int *_q)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      double *vr_max = luf->vr_max;
+      int *rs_head = luf->rs_head;
+      int *rs_next = luf->rs_next;
+      int *cs_head = luf->cs_head;
+      int *cs_prev = luf->cs_prev;
+      int *cs_next = luf->cs_next;
+      double piv_tol = luf->piv_tol;
+      int piv_lim = luf->piv_lim;
+      int suhl = luf->suhl;
+      int p, q, len, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr,
+         ncand, next_j, min_p, min_q, min_len;
+      double best, cost, big, temp;
+      /* initially no pivot candidates have been found so far */
+      p = q = 0, best = DBL_MAX, ncand = 0;
+      /* if in the active submatrix there is a column that has the only
+         non-zero (column singleton), choose it as pivot */
+      j = cs_head[1];
+      if (j != 0)
+      {  xassert(vc_len[j] == 1);
+         p = sv_ind[vc_ptr[j]], q = j;
+         goto done;
+      }
+      /* if in the active submatrix there is a row that has the only
+         non-zero (row singleton), choose it as pivot */
+      i = rs_head[1];
+      if (i != 0)
+      {  xassert(vr_len[i] == 1);
+         p = i, q = sv_ind[vr_ptr[i]];
+         goto done;
+      }
+      /* there are no singletons in the active submatrix; walk through
+         other non-empty rows and columns */
+      for (len = 2; len <= n; len++)
+      {  /* consider active columns that have len non-zeros */
+         for (j = cs_head[len]; j != 0; j = next_j)
+         {  /* the j-th column has len non-zeros */
+            j_beg = vc_ptr[j];
+            j_end = j_beg + vc_len[j] - 1;
+            /* save pointer to the next column with the same length */
+            next_j = cs_next[j];
+            /* find an element in the j-th column, which is placed in a
+               row with minimal number of non-zeros and satisfies to the
+               stability condition (such element may not exist) */
+            min_p = min_q = 0, min_len = INT_MAX;
+            for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+            {  /* get row index of v[i,j] */
+               i = sv_ind[j_ptr];
+               i_beg = vr_ptr[i];
+               i_end = i_beg + vr_len[i] - 1;
+               /* if the i-th row is not shorter than that one, where
+                  minimal element is currently placed, skip v[i,j] */
+               if (vr_len[i] >= min_len) continue;
+               /* determine the largest of absolute values of elements
+                  in the i-th row */
+               big = vr_max[i];
+               if (big < 0.0)
+               {  /* the largest value is unknown yet; compute it */
+                  for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+                  {  temp = sv_val[i_ptr];
+                     if (temp < 0.0) temp = - temp;
+                     if (big < temp) big = temp;
+                  }
+                  vr_max[i] = big;
+               }
+               /* find v[i,j] in the i-th row */
+               for (i_ptr = vr_ptr[i]; sv_ind[i_ptr] != j; i_ptr++);
+               xassert(i_ptr <= i_end);
+               /* if v[i,j] doesn't satisfy to the stability condition,
+                  skip it */
+               temp = sv_val[i_ptr];
+               if (temp < 0.0) temp = - temp;
+               if (temp < piv_tol * big) continue;
+               /* v[i,j] is better than the current minimal element */
+               min_p = i, min_q = j, min_len = vr_len[i];
+               /* if Markowitz cost of the current minimal element is
+                  not greater than (len-1)**2, it can be chosen right
+                  now; this heuristic reduces the search and works well
+                  in many cases */
+               if (min_len <= len)
+               {  p = min_p, q = min_q;
+                  goto done;
+               }
+            }
+            /* the j-th column has been scanned */
+            if (min_p != 0)
+            {  /* the minimal element is a next pivot candidate */
+               ncand++;
+               /* compute its Markowitz cost */
+               cost = (double)(min_len - 1) * (double)(len - 1);
+               /* choose between the minimal element and the current
+                  candidate */
+               if (cost < best) p = min_p, q = min_q, best = cost;
+               /* if piv_lim candidates have been considered, there are
+                  doubts that a much better candidate exists; therefore
+                  it's time to terminate the search */
+               if (ncand == piv_lim) goto done;
+            }
+            else
+            {  /* the j-th column has no elements, which satisfy to the
+                  stability condition; Uwe Suhl suggests to exclude such
+                  column from the further consideration until it becomes
+                  a column singleton; in hard cases this significantly
+                  reduces a time needed for pivot searching */
+               if (suhl)
+               {  /* remove the j-th column from the active set */
+                  if (cs_prev[j] == 0)
+                     cs_head[len] = cs_next[j];
+                  else
+                     cs_next[cs_prev[j]] = cs_next[j];
+                  if (cs_next[j] == 0)
+                     /* nop */;
+                  else
+                     cs_prev[cs_next[j]] = cs_prev[j];
+                  /* the following assignment is used to avoid an error
+                     when the routine eliminate (see below) will try to
+                     remove the j-th column from the active set */
+                  cs_prev[j] = cs_next[j] = j;
+               }
+            }
+         }
+         /* consider active rows that have len non-zeros */
+         for (i = rs_head[len]; i != 0; i = rs_next[i])
+         {  /* the i-th row has len non-zeros */
+            i_beg = vr_ptr[i];
+            i_end = i_beg + vr_len[i] - 1;
+            /* determine the largest of absolute values of elements in
+               the i-th row */
+            big = vr_max[i];
+            if (big < 0.0)
+            {  /* the largest value is unknown yet; compute it */
+               for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+               {  temp = sv_val[i_ptr];
+                  if (temp < 0.0) temp = - temp;
+                  if (big < temp) big = temp;
+               }
+               vr_max[i] = big;
+            }
+            /* find an element in the i-th row, which is placed in a
+               column with minimal number of non-zeros and satisfies to
+               the stability condition (such element always exists) */
+            min_p = min_q = 0, min_len = INT_MAX;
+            for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+            {  /* get column index of v[i,j] */
+               j = sv_ind[i_ptr];
+               /* if the j-th column is not shorter than that one, where
+                  minimal element is currently placed, skip v[i,j] */
+               if (vc_len[j] >= min_len) continue;
+               /* if v[i,j] doesn't satisfy to the stability condition,
+                  skip it */
+               temp = sv_val[i_ptr];
+               if (temp < 0.0) temp = - temp;
+               if (temp < piv_tol * big) continue;
+               /* v[i,j] is better than the current minimal element */
+               min_p = i, min_q = j, min_len = vc_len[j];
+               /* if Markowitz cost of the current minimal element is
+                  not greater than (len-1)**2, it can be chosen right
+                  now; this heuristic reduces the search and works well
+                  in many cases */
+               if (min_len <= len)
+               {  p = min_p, q = min_q;
+                  goto done;
+               }
+            }
+            /* the i-th row has been scanned */
+            if (min_p != 0)
+            {  /* the minimal element is a next pivot candidate */
+               ncand++;
+               /* compute its Markowitz cost */
+               cost = (double)(len - 1) * (double)(min_len - 1);
+               /* choose between the minimal element and the current
+                  candidate */
+               if (cost < best) p = min_p, q = min_q, best = cost;
+               /* if piv_lim candidates have been considered, there are
+                  doubts that a much better candidate exists; therefore
+                  it's time to terminate the search */
+               if (ncand == piv_lim) goto done;
+            }
+            else
+            {  /* this can't be because this can never be */
+               xassert(min_p != min_p);
+            }
+         }
+      }
+done: /* bring the pivot to the factorizing routine */
+      *_p = p, *_q = q;
+      return (p == 0);
+}
+
+/***********************************************************************
+*  eliminate - perform gaussian elimination.
+* 
+*  This routine performs elementary gaussian transformations in order
+*  to eliminate subdiagonal elements in the k-th column of the matrix
+*  U = P*V*Q using the pivot element u[k,k], where k is the number of
+*  the current elimination step.
+* 
+*  The parameters p and q are, respectively, row and column indices of
+*  the element v[p,q], which corresponds to the element u[k,k].
+* 
+*  Each time when the routine applies the elementary transformation to
+*  a non-pivot row of the matrix V, it stores the corresponding element
+*  to the matrix F in order to keep the main equality A = F*V.
+* 
+*  The routine assumes that on entry the matrices L = P*F*inv(P) and
+*  U = P*V*Q are the following:
+* 
+*        1       k                  1       k         n
+*     1  1 . . . . . . . . .     1  x x x x x x x x x x
+*        x 1 . . . . . . . .        . x x x x x x x x x
+*        x x 1 . . . . . . .        . . x x x x x x x x
+*        x x x 1 . . . . . .        . . . x x x x x x x
+*     k  x x x x 1 . . . . .     k  . . . . * * * * * *
+*        x x x x _ 1 . . . .        . . . . # * * * * *
+*        x x x x _ . 1 . . .        . . . . # * * * * *
+*        x x x x _ . . 1 . .        . . . . # * * * * *
+*        x x x x _ . . . 1 .        . . . . # * * * * *
+*     n  x x x x _ . . . . 1     n  . . . . # * * * * *
+* 
+*             matrix L                   matrix U
+* 
+*  where rows and columns of the matrix U with numbers k, k+1, ..., n
+*  form the active submatrix (eliminated elements are marked by '#' and
+*  other elements of the active submatrix are marked by '*'). Note that
+*  each eliminated non-zero element u[i,k] of the matrix U gives the
+*  corresponding element l[i,k] of the matrix L (marked by '_').
+* 
+*  Actually all operations are performed on the matrix V. Should note
+*  that the row-wise representation corresponds to the matrix V, but the
+*  column-wise representation corresponds to the active submatrix of the
+*  matrix V, i.e. elements of the matrix V, which doesn't belong to the
+*  active submatrix, are missing from the column linked lists.
+* 
+*  Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
+*  elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
+*  the following elementary gaussian transformations:
+* 
+*     (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
+* 
+*  where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
+*
+*  Additionally, in order to keep the main equality A = F*V, each time
+*  when the routine applies the transformation to i-th row of the matrix
+*  V, it also adds f[i,p] as a new element to the matrix F.
+*
+*  IMPORTANT: On entry the working arrays flag and work should contain
+*  zeros. This status is provided by the routine on exit.
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int eliminate(LUF *luf, int p, int q)
+{     int n = luf->n;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vr_cap = luf->vr_cap;
+      double *vr_piv = luf->vr_piv;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      double *vr_max = luf->vr_max;
+      int *rs_head = luf->rs_head;
+      int *rs_prev = luf->rs_prev;
+      int *rs_next = luf->rs_next;
+      int *cs_head = luf->cs_head;
+      int *cs_prev = luf->cs_prev;
+      int *cs_next = luf->cs_next;
+      int *flag = luf->flag;
+      double *work = luf->work;
+      double eps_tol = luf->eps_tol;
+      /* at this stage the row-wise representation of the matrix F is
+         not used, so fr_len can be used as a working array */
+      int *ndx = luf->fr_len;
+      int ret = 0;
+      int len, fill, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr, k,
+         p_beg, p_end, p_ptr, q_beg, q_end, q_ptr;
+      double fip, val, vpq, temp;
+      xassert(1 <= p && p <= n);
+      xassert(1 <= q && q <= n);
+      /* remove the p-th (pivot) row from the active set; this row will
+         never return there */
+      if (rs_prev[p] == 0)
+         rs_head[vr_len[p]] = rs_next[p];
+      else
+         rs_next[rs_prev[p]] = rs_next[p];
+      if (rs_next[p] == 0)
+         ;
+      else
+         rs_prev[rs_next[p]] = rs_prev[p];
+      /* remove the q-th (pivot) column from the active set; this column
+         will never return there */
+      if (cs_prev[q] == 0)
+         cs_head[vc_len[q]] = cs_next[q];
+      else
+         cs_next[cs_prev[q]] = cs_next[q];
+      if (cs_next[q] == 0)
+         ;
+      else
+         cs_prev[cs_next[q]] = cs_prev[q];
+      /* find the pivot v[p,q] = u[k,k] in the p-th row */
+      p_beg = vr_ptr[p];
+      p_end = p_beg + vr_len[p] - 1;
+      for (p_ptr = p_beg; sv_ind[p_ptr] != q; p_ptr++) /* nop */;
+      xassert(p_ptr <= p_end);
+      /* store value of the pivot */
+      vpq = (vr_piv[p] = sv_val[p_ptr]);
+      /* remove the pivot from the p-th row */
+      sv_ind[p_ptr] = sv_ind[p_end];
+      sv_val[p_ptr] = sv_val[p_end];
+      vr_len[p]--;
+      p_end--;
+      /* find the pivot v[p,q] = u[k,k] in the q-th column */
+      q_beg = vc_ptr[q];
+      q_end = q_beg + vc_len[q] - 1;
+      for (q_ptr = q_beg; sv_ind[q_ptr] != p; q_ptr++) /* nop */;
+      xassert(q_ptr <= q_end);
+      /* remove the pivot from the q-th column */
+      sv_ind[q_ptr] = sv_ind[q_end];
+      vc_len[q]--;
+      q_end--;
+      /* walk through the p-th (pivot) row, which doesn't contain the
+         pivot v[p,q] already, and do the following... */
+      for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+      {  /* get column index of v[p,j] */
+         j = sv_ind[p_ptr];
+         /* store v[p,j] to the working array */
+         flag[j] = 1;
+         work[j] = sv_val[p_ptr];
+         /* remove the j-th column from the active set; this column will
+            return there later with new length */
+         if (cs_prev[j] == 0)
+            cs_head[vc_len[j]] = cs_next[j];
+         else
+            cs_next[cs_prev[j]] = cs_next[j];
+         if (cs_next[j] == 0)
+            ;
+         else
+            cs_prev[cs_next[j]] = cs_prev[j];
+         /* find v[p,j] in the j-th column */
+         j_beg = vc_ptr[j];
+         j_end = j_beg + vc_len[j] - 1;
+         for (j_ptr = j_beg; sv_ind[j_ptr] != p; j_ptr++) /* nop */;
+         xassert(j_ptr <= j_end);
+         /* since v[p,j] leaves the active submatrix, remove it from the
+            j-th column; however, v[p,j] is kept in the p-th row */
+         sv_ind[j_ptr] = sv_ind[j_end];
+         vc_len[j]--;
+      }
+      /* walk through the q-th (pivot) column, which doesn't contain the
+         pivot v[p,q] already, and perform gaussian elimination */
+      while (q_beg <= q_end)
+      {  /* element v[i,q] should be eliminated */
+         /* get row index of v[i,q] */
+         i = sv_ind[q_beg];
+         /* remove the i-th row from the active set; later this row will
+            return there with new length */
+         if (rs_prev[i] == 0)
+            rs_head[vr_len[i]] = rs_next[i];
+         else
+            rs_next[rs_prev[i]] = rs_next[i];
+         if (rs_next[i] == 0)
+            ;
+         else
+            rs_prev[rs_next[i]] = rs_prev[i];
+         /* find v[i,q] in the i-th row */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; sv_ind[i_ptr] != q; i_ptr++) /* nop */;
+         xassert(i_ptr <= i_end);
+         /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] */
+         fip = sv_val[i_ptr] / vpq;
+         /* since v[i,q] should be eliminated, remove it from the i-th
+            row */
+         sv_ind[i_ptr] = sv_ind[i_end];
+         sv_val[i_ptr] = sv_val[i_end];
+         vr_len[i]--;
+         i_end--;
+         /* and from the q-th column */
+         sv_ind[q_beg] = sv_ind[q_end];
+         vc_len[q]--;
+         q_end--;
+         /* perform gaussian transformation:
+            (i-th row) := (i-th row) - f[i,p] * (p-th row)
+            note that now the p-th row, which is in the working array,
+            doesn't contain the pivot v[p,q], and the i-th row doesn't
+            contain the eliminated element v[i,q] */
+         /* walk through the i-th row and transform existing non-zero
+            elements */
+         fill = vr_len[p];
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         {  /* get column index of v[i,j] */
+            j = sv_ind[i_ptr];
+            /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
+            if (flag[j])
+            {  /* v[p,j] != 0 */
+               temp = (sv_val[i_ptr] -= fip * work[j]);
+               if (temp < 0.0) temp = - temp;
+               flag[j] = 0;
+               fill--; /* since both v[i,j] and v[p,j] exist */
+               if (temp == 0.0 || temp < eps_tol)
+               {  /* new v[i,j] is closer to zero; replace it by exact
+                     zero, i.e. remove it from the active submatrix */
+                  /* remove v[i,j] from the i-th row */
+                  sv_ind[i_ptr] = sv_ind[i_end];
+                  sv_val[i_ptr] = sv_val[i_end];
+                  vr_len[i]--;
+                  i_ptr--;
+                  i_end--;
+                  /* find v[i,j] in the j-th column */
+                  j_beg = vc_ptr[j];
+                  j_end = j_beg + vc_len[j] - 1;
+                  for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++);
+                  xassert(j_ptr <= j_end);
+                  /* remove v[i,j] from the j-th column */
+                  sv_ind[j_ptr] = sv_ind[j_end];
+                  vc_len[j]--;
+               }
+               else
+               {  /* v_big := max(v_big, |v[i,j]|) */
+                  if (luf->big_v < temp) luf->big_v = temp;
+               }
+            }
+         }
+         /* now flag is the pattern of the set v[p,*] \ v[i,*], and fill
+            is number of non-zeros in this set; therefore up to fill new
+            non-zeros may appear in the i-th row */
+         if (vr_len[i] + fill > vr_cap[i])
+         {  /* enlarge the i-th row */
+            if (luf_enlarge_row(luf, i, vr_len[i] + fill))
+            {  /* overflow of the sparse vector area */
+               ret = 1;
+               goto done;
+            }
+            /* defragmentation may change row and column pointers of the
+               matrix V */
+            p_beg = vr_ptr[p];
+            p_end = p_beg + vr_len[p] - 1;
+            q_beg = vc_ptr[q];
+            q_end = q_beg + vc_len[q] - 1;
+         }
+         /* walk through the p-th (pivot) row and create new elements
+            of the i-th row that appear due to fill-in; column indices
+            of these new elements are accumulated in the array ndx */
+         len = 0;
+         for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+         {  /* get column index of v[p,j], which may cause fill-in */
+            j = sv_ind[p_ptr];
+            if (flag[j])
+            {  /* compute new non-zero v[i,j] = 0 - f[i,p] * v[p,j] */
+               temp = (val = - fip * work[j]);
+               if (temp < 0.0) temp = - temp;
+               if (temp == 0.0 || temp < eps_tol)
+                  /* if v[i,j] is closer to zero; just ignore it */;
+               else
+               {  /* add v[i,j] to the i-th row */
+                  i_ptr = vr_ptr[i] + vr_len[i];
+                  sv_ind[i_ptr] = j;
+                  sv_val[i_ptr] = val;
+                  vr_len[i]++;
+                  /* remember column index of v[i,j] */
+                  ndx[++len] = j;
+                  /* big_v := max(big_v, |v[i,j]|) */
+                  if (luf->big_v < temp) luf->big_v = temp;
+               }
+            }
+            else
+            {  /* there is no fill-in, because v[i,j] already exists in
+                  the i-th row; restore the flag of the element v[p,j],
+                  which was reset before */
+               flag[j] = 1;
+            }
+         }
+         /* add new non-zeros v[i,j] to the corresponding columns */
+         for (k = 1; k <= len; k++)
+         {  /* get column index of new non-zero v[i,j] */
+            j = ndx[k];
+            /* one free location is needed in the j-th column */
+            if (vc_len[j] + 1 > vc_cap[j])
+            {  /* enlarge the j-th column */
+               if (luf_enlarge_col(luf, j, vc_len[j] + 10))
+               {  /* overflow of the sparse vector area */
+                  ret = 1;
+                  goto done;
+               }
+               /* defragmentation may change row and column pointers of
+                  the matrix V */
+               p_beg = vr_ptr[p];
+               p_end = p_beg + vr_len[p] - 1;
+               q_beg = vc_ptr[q];
+               q_end = q_beg + vc_len[q] - 1;
+            }
+            /* add new non-zero v[i,j] to the j-th column */
+            j_ptr = vc_ptr[j] + vc_len[j];
+            sv_ind[j_ptr] = i;
+            vc_len[j]++;
+         }
+         /* now the i-th row has been completely transformed, therefore
+            it can return to the active set with new length */
+         rs_prev[i] = 0;
+         rs_next[i] = rs_head[vr_len[i]];
+         if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
+         rs_head[vr_len[i]] = i;
+         /* the largest of absolute values of elements in the i-th row
+            is currently unknown */
+         vr_max[i] = -1.0;
+         /* at least one free location is needed to store the gaussian
+            multiplier */
+         if (luf->sv_end - luf->sv_beg < 1)
+         {  /* there are no free locations at all; defragment SVA */
+            luf_defrag_sva(luf);
+            if (luf->sv_end - luf->sv_beg < 1)
+            {  /* overflow of the sparse vector area */
+               ret = 1;
+               goto done;
+            }
+            /* defragmentation may change row and column pointers of the
+               matrix V */
+            p_beg = vr_ptr[p];
+            p_end = p_beg + vr_len[p] - 1;
+            q_beg = vc_ptr[q];
+            q_end = q_beg + vc_len[q] - 1;
+         }
+         /* add the element f[i,p], which is the gaussian multiplier,
+            to the matrix F */
+         luf->sv_end--;
+         sv_ind[luf->sv_end] = i;
+         sv_val[luf->sv_end] = fip;
+         fc_len[p]++;
+         /* end of elimination loop */
+      }
+      /* at this point the q-th (pivot) column should be empty */
+      xassert(vc_len[q] == 0);
+      /* reset capacity of the q-th column */
+      vc_cap[q] = 0;
+      /* remove node of the q-th column from the addressing list */
+      k = n + q;
+      if (sv_prev[k] == 0)
+         luf->sv_head = sv_next[k];
+      else
+         sv_next[sv_prev[k]] = sv_next[k];
+      if (sv_next[k] == 0)
+         luf->sv_tail = sv_prev[k];
+      else
+         sv_prev[sv_next[k]] = sv_prev[k];
+      /* the p-th column of the matrix F has been completely built; set
+         its pointer */
+      fc_ptr[p] = luf->sv_end;
+      /* walk through the p-th (pivot) row and do the following... */
+      for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
+      {  /* get column index of v[p,j] */
+         j = sv_ind[p_ptr];
+         /* erase v[p,j] from the working array */
+         flag[j] = 0;
+         work[j] = 0.0;
+         /* the j-th column has been completely transformed, therefore
+            it can return to the active set with new length; however
+            the special case c_prev[j] = c_next[j] = j means that the
+            routine find_pivot excluded the j-th column from the active
+            set due to Uwe Suhl's rule, and therefore in this case the
+            column can return to the active set only if it is a column
+            singleton */
+         if (!(vc_len[j] != 1 && cs_prev[j] == j && cs_next[j] == j))
+         {  cs_prev[j] = 0;
+            cs_next[j] = cs_head[vc_len[j]];
+            if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
+            cs_head[vc_len[j]] = j;
+         }
+      }
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  build_v_cols - build the matrix V in column-wise format
+*
+*  This routine builds the column-wise representation of the matrix V
+*  using its row-wise representation.
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int build_v_cols(LUF *luf)
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *vc_cap = luf->vc_cap;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int *sv_prev = luf->sv_prev;
+      int *sv_next = luf->sv_next;
+      int ret = 0;
+      int i, i_beg, i_end, i_ptr, j, j_ptr, k, nnz;
+      /* it is assumed that on entry all columns of the matrix V are
+         empty, i.e. vc_len[j] = vc_cap[j] = 0 for all j = 1, ..., n,
+         and have been removed from the addressing list */
+      /* count non-zeros in columns of the matrix V; count total number
+         of non-zeros in this matrix */
+      nnz = 0;
+      for (i = 1; i <= n; i++)
+      {  /* walk through elements of the i-th row and count non-zeros
+            in the corresponding columns */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+            vc_cap[sv_ind[i_ptr]]++;
+         /* count total number of non-zeros */
+         nnz += vr_len[i];
+      }
+      /* store total number of non-zeros */
+      luf->nnz_v = nnz;
+      /* check for free locations */
+      if (luf->sv_end - luf->sv_beg < nnz)
+      {  /* overflow of the sparse vector area */
+         ret = 1;
+         goto done;
+      }
+      /* allocate columns of the matrix V */
+      for (j = 1; j <= n; j++)
+      {  /* set pointer to the j-th column */
+         vc_ptr[j] = luf->sv_beg;
+         /* reserve locations for the j-th column */
+         luf->sv_beg += vc_cap[j];
+      }
+      /* build the matrix V in column-wise format using this matrix in
+         row-wise format */
+      for (i = 1; i <= n; i++)
+      {  /* walk through elements of the i-th row */
+         i_beg = vr_ptr[i];
+         i_end = i_beg + vr_len[i] - 1;
+         for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
+         {  /* get column index */
+            j = sv_ind[i_ptr];
+            /* store element in the j-th column */
+            j_ptr = vc_ptr[j] + vc_len[j];
+            sv_ind[j_ptr] = i;
+            sv_val[j_ptr] = sv_val[i_ptr];
+            /* increase length of the j-th column */
+            vc_len[j]++;
+         }
+      }
+      /* now columns are placed in the sparse vector area behind rows
+         in the order n+1, n+2, ..., n+n; so insert column nodes in the
+         addressing list using this order */
+      for (k = n+1; k <= n+n; k++)
+      {  sv_prev[k] = k-1;
+         sv_next[k] = k+1;
+      }
+      sv_prev[n+1] = luf->sv_tail;
+      sv_next[luf->sv_tail] = n+1;
+      sv_next[n+n] = 0;
+      luf->sv_tail = n+n;
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  build_f_rows - build the matrix F in row-wise format
+*
+*  This routine builds the row-wise representation of the matrix F using
+*  its column-wise representation.
+*
+*  If no error occured, the routine returns zero. Otherwise, in case of
+*  overflow of the sparse vector area, the routine returns non-zero. */
+
+static int build_f_rows(LUF *luf)
+{     int n = luf->n;
+      int *fr_ptr = luf->fr_ptr;
+      int *fr_len = luf->fr_len;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int ret = 0;
+      int i, j, j_beg, j_end, j_ptr, ptr, nnz;
+      /* clear rows of the matrix F */
+      for (i = 1; i <= n; i++) fr_len[i] = 0;
+      /* count non-zeros in rows of the matrix F; count total number of
+         non-zeros in this matrix */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  /* walk through elements of the j-th column and count non-zeros
+            in the corresponding rows */
+         j_beg = fc_ptr[j];
+         j_end = j_beg + fc_len[j] - 1;
+         for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+            fr_len[sv_ind[j_ptr]]++;
+         /* increase total number of non-zeros */
+         nnz += fc_len[j];
+      }
+      /* store total number of non-zeros */
+      luf->nnz_f = nnz;
+      /* check for free locations */
+      if (luf->sv_end - luf->sv_beg < nnz)
+      {  /* overflow of the sparse vector area */
+         ret = 1;
+         goto done;
+      }
+      /* allocate rows of the matrix F */
+      for (i = 1; i <= n; i++)
+      {  /* set pointer to the end of the i-th row; later this pointer
+            will be set to the beginning of the i-th row */
+         fr_ptr[i] = luf->sv_end;
+         /* reserve locations for the i-th row */
+         luf->sv_end -= fr_len[i];
+      }
+      /* build the matrix F in row-wise format using this matrix in
+         column-wise format */
+      for (j = 1; j <= n; j++)
+      {  /* walk through elements of the j-th column */
+         j_beg = fc_ptr[j];
+         j_end = j_beg + fc_len[j] - 1;
+         for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
+         {  /* get row index */
+            i = sv_ind[j_ptr];
+            /* store element in the i-th row */
+            ptr = --fr_ptr[i];
+            sv_ind[ptr] = j;
+            sv_val[ptr] = sv_val[j_ptr];
+         }
+      }
+done: /* return to the factorizing routine */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_factorize - compute LU-factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
+*     int ind[], double val[]), void *info);
+*
+*  DESCRIPTION
+*
+*  The routine luf_factorize computes LU-factorization of a specified
+*  square matrix A.
+*
+*  The parameter luf specifies LU-factorization program object created
+*  by the routine luf_create_it.
+*
+*  The parameter n specifies the order of A, n > 0.
+*
+*  The formal routine col specifies the matrix A to be factorized. To
+*  obtain j-th column of A the routine luf_factorize calls the routine
+*  col with the parameter j (1 <= j <= n). In response the routine col
+*  should store row indices and numerical values of non-zero elements
+*  of j-th column of A to locations ind[1,...,len] and val[1,...,len],
+*  respectively, where len is the number of non-zeros in j-th column
+*  returned on exit. Neither zero nor duplicate elements are allowed.
+*
+*  The parameter info is a transit pointer passed to the routine col.
+*
+*  RETURNS
+*
+*  0  LU-factorization has been successfully computed.
+*
+*  LUF_ESING
+*     The specified matrix is singular within the working precision.
+*     (On some elimination step the active submatrix is exactly zero,
+*     so no pivot can be chosen.)
+*
+*  LUF_ECOND
+*     The specified matrix is ill-conditioned.
+*     (On some elimination step too intensive growth of elements of the
+*     active submatix has been detected.)
+*
+*  If matrix A is well scaled, the return code LUF_ECOND may also mean
+*  that the threshold pivoting tolerance piv_tol should be increased.
+*
+*  In case of non-zero return code the factorization becomes invalid.
+*  It should not be used in other operations until the cause of failure
+*  has been eliminated and the factorization has been recomputed again
+*  with the routine luf_factorize.
+*
+*  REPAIRING SINGULAR MATRIX
+*
+*  If the routine luf_factorize returns non-zero code, it provides all
+*  necessary information that can be used for "repairing" the matrix A,
+*  where "repairing" means replacing linearly dependent columns of the
+*  matrix A by appropriate columns of the unity matrix. This feature is
+*  needed when this routine is used for factorizing the basis matrix
+*  within the simplex method procedure.
+*
+*  On exit linearly dependent columns of the (partially transformed)
+*  matrix U have numbers rank+1, rank+2, ..., n, where rank is estimated
+*  rank of the matrix A stored by the routine to the member luf->rank.
+*  The correspondence between columns of A and U is the same as between
+*  columns of V and U. Thus, linearly dependent columns of the matrix A
+*  have numbers qq_col[rank+1], qq_col[rank+2], ..., qq_col[n], where
+*  qq_col is the column-like representation of the permutation matrix Q.
+*  It is understood that each j-th linearly dependent column of the
+*  matrix U should be replaced by the unity vector, where all elements
+*  are zero except the unity diagonal element u[j,j]. On the other hand
+*  j-th row of the matrix U corresponds to the row of the matrix V (and
+*  therefore of the matrix A) with the number pp_row[j], where pp_row is
+*  the row-like representation of the permutation matrix P. Thus, each
+*  j-th linearly dependent column of the matrix U should be replaced by
+*  column of the unity matrix with the number pp_row[j].
+*
+*  The code that repairs the matrix A may look like follows:
+*
+*     for (j = rank+1; j <= n; j++)
+*     {  replace the column qq_col[j] of the matrix A by the column
+*        pp_row[j] of the unity matrix;
+*     }
+*
+*  where rank, pp_row, and qq_col are members of the structure LUF. */
+
+int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info)
+{     int *pp_row, *pp_col, *qq_row, *qq_col;
+      double max_gro = luf->max_gro;
+      int i, j, k, p, q, t, ret;
+      if (n < 1)
+         xfault("luf_factorize: n = %d; invalid parameter\n", n);
+      if (n > N_MAX)
+         xfault("luf_factorize: n = %d; matrix too big\n", n);
+      /* invalidate the factorization */
+      luf->valid = 0;
+      /* reallocate arrays, if necessary */
+      reallocate(luf, n);
+      pp_row = luf->pp_row;
+      pp_col = luf->pp_col;
+      qq_row = luf->qq_row;
+      qq_col = luf->qq_col;
+      /* estimate initial size of the SVA, if not specified */
+      if (luf->sv_size == 0 && luf->new_sva == 0)
+         luf->new_sva = 5 * (n + 10);
+more: /* reallocate the sparse vector area, if required */
+      if (luf->new_sva > 0)
+      {  if (luf->sv_ind != NULL) xfree(luf->sv_ind);
+         if (luf->sv_val != NULL) xfree(luf->sv_val);
+         luf->sv_size = luf->new_sva;
+         luf->sv_ind = xcalloc(1+luf->sv_size, sizeof(int));
+         luf->sv_val = xcalloc(1+luf->sv_size, sizeof(double));
+         luf->new_sva = 0;
+      }
+      /* initialize LU-factorization data structures */
+      if (initialize(luf, col, info))
+      {  /* overflow of the sparse vector area */
+         luf->new_sva = luf->sv_size + luf->sv_size;
+         xassert(luf->new_sva > luf->sv_size);
+         goto more;
+      }
+      /* main elimination loop */
+      for (k = 1; k <= n; k++)
+      {  /* choose a pivot element v[p,q] */
+         if (find_pivot(luf, &p, &q))
+         {  /* no pivot can be chosen, because the active submatrix is
+               exactly zero */
+            luf->rank = k - 1;
+            ret = LUF_ESING;
+            goto done;
+         }
+         /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
+            rows and k-th and j'-th columns of the matrix U = P*V*Q to
+            move the element u[i',j'] to the position u[k,k] */
+         i = pp_col[p], j = qq_row[q];
+         xassert(k <= i && i <= n && k <= j && j <= n);
+         /* permute k-th and i-th rows of the matrix U */
+         t = pp_row[k];
+         pp_row[i] = t, pp_col[t] = i;
+         pp_row[k] = p, pp_col[p] = k;
+         /* permute k-th and j-th columns of the matrix U */
+         t = qq_col[k];
+         qq_col[j] = t, qq_row[t] = j;
+         qq_col[k] = q, qq_row[q] = k;
+         /* eliminate subdiagonal elements of k-th column of the matrix
+            U = P*V*Q using the pivot element u[k,k] = v[p,q] */
+         if (eliminate(luf, p, q))
+         {  /* overflow of the sparse vector area */
+            luf->new_sva = luf->sv_size + luf->sv_size;
+            xassert(luf->new_sva > luf->sv_size);
+            goto more;
+         }
+         /* check relative growth of elements of the matrix V */
+         if (luf->big_v > max_gro * luf->max_a)
+         {  /* the growth is too intensive, therefore most probably the
+               matrix A is ill-conditioned */
+            luf->rank = k - 1;
+            ret = LUF_ECOND;
+            goto done;
+         }
+      }
+      /* now the matrix U = P*V*Q is upper triangular, the matrix V has
+         been built in row-wise format, and the matrix F has been built
+         in column-wise format */
+      /* defragment the sparse vector area in order to merge all free
+         locations in one continuous extent */
+      luf_defrag_sva(luf);
+      /* build the matrix V in column-wise format */
+      if (build_v_cols(luf))
+      {  /* overflow of the sparse vector area */
+         luf->new_sva = luf->sv_size + luf->sv_size;
+         xassert(luf->new_sva > luf->sv_size);
+         goto more;
+      }
+      /* build the matrix F in row-wise format */
+      if (build_f_rows(luf))
+      {  /* overflow of the sparse vector area */
+         luf->new_sva = luf->sv_size + luf->sv_size;
+         xassert(luf->new_sva > luf->sv_size);
+         goto more;
+      }
+      /* the LU-factorization has been successfully computed */
+      luf->valid = 1;
+      luf->rank = n;
+      ret = 0;
+      /* if there are few free locations in the sparse vector area, try
+         increasing its size in the future */
+      t = 3 * (n + luf->nnz_v) + 2 * luf->nnz_f;
+      if (luf->sv_size < t)
+      {  luf->new_sva = luf->sv_size;
+         while (luf->new_sva < t)
+         {  k = luf->new_sva;
+            luf->new_sva = k + k;
+            xassert(luf->new_sva > k);
+         }
+      }
+done: /* return to the calling program */
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_f_solve - solve system F*x = b or F'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_f_solve(LUF *luf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine luf_f_solve solves either the system F*x = b (if the
+*  flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
+*  where the matrix F is a component of LU-factorization specified by
+*  the parameter luf, F' is a matrix transposed to F.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[n], where n is the order of the
+*  matrix F. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void luf_f_solve(LUF *luf, int tr, double x[])
+{     int n = luf->n;
+      int *fr_ptr = luf->fr_ptr;
+      int *fr_len = luf->fr_len;
+      int *fc_ptr = luf->fc_ptr;
+      int *fc_len = luf->fc_len;
+      int *pp_row = luf->pp_row;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      int i, j, k, beg, end, ptr;
+      double xk;
+      if (!luf->valid)
+         xfault("luf_f_solve: LU-factorization is not valid\n");
+      if (!tr)
+      {  /* solve the system F*x = b */
+         for (j = 1; j <= n; j++)
+         {  k = pp_row[j];
+            xk = x[k];
+            if (xk != 0.0)
+            {  beg = fc_ptr[k];
+               end = beg + fc_len[k] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  x[sv_ind[ptr]] -= sv_val[ptr] * xk;
+            }
+         }
+      }
+      else
+      {  /* solve the system F'*x = b */
+         for (i = n; i >= 1; i--)
+         {  k = pp_row[i];
+            xk = x[k];
+            if (xk != 0.0)
+            {  beg = fr_ptr[k];
+               end = beg + fr_len[k] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  x[sv_ind[ptr]] -= sv_val[ptr] * xk;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_v_solve - solve system V*x = b or V'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_v_solve(LUF *luf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine luf_v_solve solves either the system V*x = b (if the
+*  flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
+*  where the matrix V is a component of LU-factorization specified by
+*  the parameter luf, V' is a matrix transposed to V.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[n], where n is the order of the
+*  matrix V. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void luf_v_solve(LUF *luf, int tr, double x[])
+{     int n = luf->n;
+      int *vr_ptr = luf->vr_ptr;
+      int *vr_len = luf->vr_len;
+      double *vr_piv = luf->vr_piv;
+      int *vc_ptr = luf->vc_ptr;
+      int *vc_len = luf->vc_len;
+      int *pp_row = luf->pp_row;
+      int *qq_col = luf->qq_col;
+      int *sv_ind = luf->sv_ind;
+      double *sv_val = luf->sv_val;
+      double *b = luf->work;
+      int i, j, k, beg, end, ptr;
+      double temp;
+      if (!luf->valid)
+         xfault("luf_v_solve: LU-factorization is not valid\n");
+      for (k = 1; k <= n; k++) b[k] = x[k], x[k] = 0.0;
+      if (!tr)
+      {  /* solve the system V*x = b */
+         for (k = n; k >= 1; k--)
+         {  i = pp_row[k], j = qq_col[k];
+            temp = b[i];
+            if (temp != 0.0)
+            {  x[j] = (temp /= vr_piv[i]);
+               beg = vc_ptr[j];
+               end = beg + vc_len[j] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  b[sv_ind[ptr]] -= sv_val[ptr] * temp;
+            }
+         }
+      }
+      else
+      {  /* solve the system V'*x = b */
+         for (k = 1; k <= n; k++)
+         {  i = pp_row[k], j = qq_col[k];
+            temp = b[j];
+            if (temp != 0.0)
+            {  x[i] = (temp /= vr_piv[i]);
+               beg = vr_ptr[i];
+               end = beg + vr_len[i] - 1;
+               for (ptr = beg; ptr <= end; ptr++)
+                  b[sv_ind[ptr]] -= sv_val[ptr] * temp;
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_a_solve - solve system A*x = b or A'*x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_a_solve(LUF *luf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine luf_a_solve solves either the system A*x = b (if the
+*  flag tr is zero) or the system A'*x = b (if the flag tr is non-zero),
+*  where the parameter luf specifies LU-factorization of the matrix A,
+*  A' is a matrix transposed to A.
+*
+*  On entry the array x should contain elements of the right-hand side
+*  vector b in locations x[1], ..., x[n], where n is the order of the
+*  matrix A. On exit this array will contain elements of the solution
+*  vector x in the same locations. */
+
+void luf_a_solve(LUF *luf, int tr, double x[])
+{     if (!luf->valid)
+         xfault("luf_a_solve: LU-factorization is not valid\n");
+      if (!tr)
+      {  /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
+         luf_f_solve(luf, 0, x);
+         luf_v_solve(luf, 0, x);
+      }
+      else
+      {  /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
+         luf_v_solve(luf, 1, x);
+         luf_f_solve(luf, 1, x);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  luf_delete_it - delete LU-factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpluf.h"
+*  void luf_delete_it(LUF *luf);
+*
+*  DESCRIPTION
+*
+*  The routine luf_delete deletes LU-factorization specified by the
+*  parameter luf and frees all the memory allocated to this program
+*  object. */
+
+void luf_delete_it(LUF *luf)
+{     if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
+      if (luf->fr_len != NULL) xfree(luf->fr_len);
+      if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
+      if (luf->fc_len != NULL) xfree(luf->fc_len);
+      if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
+      if (luf->vr_len != NULL) xfree(luf->vr_len);
+      if (luf->vr_cap != NULL) xfree(luf->vr_cap);
+      if (luf->vr_piv != NULL) xfree(luf->vr_piv);
+      if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
+      if (luf->vc_len != NULL) xfree(luf->vc_len);
+      if (luf->vc_cap != NULL) xfree(luf->vc_cap);
+      if (luf->pp_row != NULL) xfree(luf->pp_row);
+      if (luf->pp_col != NULL) xfree(luf->pp_col);
+      if (luf->qq_row != NULL) xfree(luf->qq_row);
+      if (luf->qq_col != NULL) xfree(luf->qq_col);
+      if (luf->sv_ind != NULL) xfree(luf->sv_ind);
+      if (luf->sv_val != NULL) xfree(luf->sv_val);
+      if (luf->sv_prev != NULL) xfree(luf->sv_prev);
+      if (luf->sv_next != NULL) xfree(luf->sv_next);
+      if (luf->vr_max != NULL) xfree(luf->vr_max);
+      if (luf->rs_head != NULL) xfree(luf->rs_head);
+      if (luf->rs_prev != NULL) xfree(luf->rs_prev);
+      if (luf->rs_next != NULL) xfree(luf->rs_next);
+      if (luf->cs_head != NULL) xfree(luf->cs_head);
+      if (luf->cs_prev != NULL) xfree(luf->cs_prev);
+      if (luf->cs_next != NULL) xfree(luf->cs_next);
+      if (luf->flag != NULL) xfree(luf->flag);
+      if (luf->work != NULL) xfree(luf->work);
+      xfree(luf);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpluf.h
===================================================================
--- deps/glpk/src/glpluf.h	(revision 9)
+++ deps/glpk/src/glpluf.h	(revision 9)
@@ -0,0 +1,326 @@
+/* glpluf.h (LU-factorization) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPLUF_H
+#define GLPLUF_H
+
+/***********************************************************************
+*  The structure LUF defines LU-factorization of a square matrix A and
+*  is the following quartet:
+*
+*     [A] = (F, V, P, Q),                                            (1)
+*
+*  where F and V are such matrices that
+*
+*     A = F * V,                                                     (2)
+*
+*  and P and Q are such permutation matrices that the matrix
+*
+*     L = P * F * inv(P)                                             (3)
+*
+*  is lower triangular with unity diagonal, and the matrix
+*
+*     U = P * V * Q                                                  (4)
+*
+*  is upper triangular. All the matrices have the order n.
+*
+*  Matrices F and V are stored in row- and column-wise sparse format
+*  as row and column linked lists of non-zero elements. Unity elements
+*  on the main diagonal of matrix F are not stored. Pivot elements of
+*  matrix V (which correspond to diagonal elements of matrix U) are
+*  stored separately in an ordinary array.
+*
+*  Permutation matrices P and Q are stored in ordinary arrays in both
+*  row- and column-like formats.
+*
+*  Matrices L and U are completely defined by matrices F, V, P, and Q
+*  and therefore not stored explicitly.
+*
+*  The factorization (1)-(4) is a version of LU-factorization. Indeed,
+*  from (3) and (4) it follows that:
+*
+*     F = inv(P) * L * P,
+*
+*     U = inv(P) * U * inv(Q),
+*
+*  and substitution into (2) leads to:
+*
+*     A = F * V = inv(P) * L * U * inv(Q).
+*
+*  For more details see the program documentation. */
+
+typedef struct LUF LUF;
+
+struct LUF
+{     /* LU-factorization of a square matrix */
+      int n_max;
+      /* maximal value of n (increased automatically, if necessary) */
+      int n;
+      /* the order of matrices A, F, V, P, Q */
+      int valid;
+      /* the factorization is valid only if this flag is set */
+      /*--------------------------------------------------------------*/
+      /* matrix F in row-wise format */
+      int *fr_ptr; /* int fr_ptr[1+n_max]; */
+      /* fr_ptr[i], i = 1,...,n, is a pointer to the first element of
+         i-th row in SVA */
+      int *fr_len; /* int fr_len[1+n_max]; */
+      /* fr_len[i], i = 1,...,n, is the number of elements in i-th row
+         (except unity diagonal element) */
+      /*--------------------------------------------------------------*/
+      /* matrix F in column-wise format */
+      int *fc_ptr; /* int fc_ptr[1+n_max]; */
+      /* fc_ptr[j], j = 1,...,n, is a pointer to the first element of
+         j-th column in SVA */
+      int *fc_len; /* int fc_len[1+n_max]; */
+      /* fc_len[j], j = 1,...,n, is the number of elements in j-th
+         column (except unity diagonal element) */
+      /*--------------------------------------------------------------*/
+      /* matrix V in row-wise format */
+      int *vr_ptr; /* int vr_ptr[1+n_max]; */
+      /* vr_ptr[i], i = 1,...,n, is a pointer to the first element of
+         i-th row in SVA */
+      int *vr_len; /* int vr_len[1+n_max]; */
+      /* vr_len[i], i = 1,...,n, is the number of elements in i-th row
+         (except pivot element) */
+      int *vr_cap; /* int vr_cap[1+n_max]; */
+      /* vr_cap[i], i = 1,...,n, is the capacity of i-th row, i.e.
+         maximal number of elements which can be stored in the row
+         without relocating it, vr_cap[i] >= vr_len[i] */
+      double *vr_piv; /* double vr_piv[1+n_max]; */
+      /* vr_piv[p], p = 1,...,n, is the pivot element v[p,q] which
+         corresponds to a diagonal element of matrix U = P*V*Q */
+      /*--------------------------------------------------------------*/
+      /* matrix V in column-wise format */
+      int *vc_ptr; /* int vc_ptr[1+n_max]; */
+      /* vc_ptr[j], j = 1,...,n, is a pointer to the first element of
+         j-th column in SVA */
+      int *vc_len; /* int vc_len[1+n_max]; */
+      /* vc_len[j], j = 1,...,n, is the number of elements in j-th
+         column (except pivot element) */
+      int *vc_cap; /* int vc_cap[1+n_max]; */
+      /* vc_cap[j], j = 1,...,n, is the capacity of j-th column, i.e.
+         maximal number of elements which can be stored in the column
+         without relocating it, vc_cap[j] >= vc_len[j] */
+      /*--------------------------------------------------------------*/
+      /* matrix P */
+      int *pp_row; /* int pp_row[1+n_max]; */
+      /* pp_row[i] = j means that P[i,j] = 1 */
+      int *pp_col; /* int pp_col[1+n_max]; */
+      /* pp_col[j] = i means that P[i,j] = 1 */
+      /* if i-th row or column of matrix F is i'-th row or column of
+         matrix L, or if i-th row of matrix V is i'-th row of matrix U,
+         then pp_row[i'] = i and pp_col[i] = i' */
+      /*--------------------------------------------------------------*/
+      /* matrix Q */
+      int *qq_row; /* int qq_row[1+n_max]; */
+      /* qq_row[i] = j means that Q[i,j] = 1 */
+      int *qq_col; /* int qq_col[1+n_max]; */
+      /* qq_col[j] = i means that Q[i,j] = 1 */
+      /* if j-th column of matrix V is j'-th column of matrix U, then
+         qq_row[j] = j' and qq_col[j'] = j */
+      /*--------------------------------------------------------------*/
+      /* the Sparse Vector Area (SVA) is a set of locations used to
+         store sparse vectors representing rows and columns of matrices
+         F and V; each location is a doublet (ind, val), where ind is
+         an index, and val is a numerical value of a sparse vector
+         element; in the whole each sparse vector is a set of adjacent
+         locations defined by a pointer to the first element and the
+         number of elements; these pointer and number are stored in the
+         corresponding matrix data structure (see above); the left part
+         of SVA is used to store rows and columns of matrix V, and its
+         right part is used to store rows and columns of matrix F; the
+         middle part of SVA contains free (unused) locations */
+      int sv_size;
+      /* the size of SVA, in locations; all locations are numbered by
+         integers 1, ..., n, and location 0 is not used; if necessary,
+         the SVA size is automatically increased */
+      int sv_beg, sv_end;
+      /* SVA partitioning pointers:
+         locations from 1 to sv_beg-1 belong to the left part
+         locations from sv_beg to sv_end-1 belong to the middle part
+         locations from sv_end to sv_size belong to the right part
+         the size of the middle part is (sv_end - sv_beg) */
+      int *sv_ind; /* sv_ind[1+sv_size]; */
+      /* sv_ind[k], 1 <= k <= sv_size, is the index field of k-th
+         location */
+      double *sv_val; /* sv_val[1+sv_size]; */
+      /* sv_val[k], 1 <= k <= sv_size, is the value field of k-th
+         location */
+      /*--------------------------------------------------------------*/
+      /* in order to efficiently defragment the left part of SVA there
+         is a doubly linked list of rows and columns of matrix V, where
+         rows are numbered by 1, ..., n, while columns are numbered by
+         n+1, ..., n+n, that allows uniquely identifying each row and
+         column of V by only one integer; in this list rows and columns
+         are ordered by ascending their pointers vr_ptr and vc_ptr */
+      int sv_head;
+      /* the number of leftmost row/column */
+      int sv_tail;
+      /* the number of rightmost row/column */
+      int *sv_prev; /* int sv_prev[1+n_max+n_max]; */
+      /* sv_prev[k], k = 1,...,n+n, is the number of a row/column which
+         precedes k-th row/column */
+      int *sv_next; /* int sv_next[1+n_max+n_max]; */
+      /* sv_next[k], k = 1,...,n+n, is the number of a row/column which
+         succedes k-th row/column */
+      /*--------------------------------------------------------------*/
+      /* working segment (used only during factorization) */
+      double *vr_max; /* int vr_max[1+n_max]; */
+      /* vr_max[i], 1 <= i <= n, is used only if i-th row of matrix V
+         is active (i.e. belongs to the active submatrix), and is the
+         largest magnitude of elements in i-th row; if vr_max[i] < 0,
+         the largest magnitude is not known yet and should be computed
+         by the pivoting routine */
+      /*--------------------------------------------------------------*/
+      /* in order to efficiently implement Markowitz strategy and Duff
+         search technique there are two families {R[0], R[1], ..., R[n]}
+         and {C[0], C[1], ..., C[n]}; member R[k] is the set of active
+         rows of matrix V, which have k non-zeros, and member C[k] is
+         the set of active columns of V, which have k non-zeros in the
+         active submatrix (i.e. in the active rows); each set R[k] and
+         C[k] is implemented as a separate doubly linked list */
+      int *rs_head; /* int rs_head[1+n_max]; */
+      /* rs_head[k], 0 <= k <= n, is the number of first active row,
+         which has k non-zeros */
+      int *rs_prev; /* int rs_prev[1+n_max]; */
+      /* rs_prev[i], 1 <= i <= n, is the number of previous row, which
+         has the same number of non-zeros as i-th row */
+      int *rs_next; /* int rs_next[1+n_max]; */
+      /* rs_next[i], 1 <= i <= n, is the number of next row, which has
+         the same number of non-zeros as i-th row */
+      int *cs_head; /* int cs_head[1+n_max]; */
+      /* cs_head[k], 0 <= k <= n, is the number of first active column,
+         which has k non-zeros (in the active rows) */
+      int *cs_prev; /* int cs_prev[1+n_max]; */
+      /* cs_prev[j], 1 <= j <= n, is the number of previous column,
+         which has the same number of non-zeros (in the active rows) as
+         j-th column */
+      int *cs_next; /* int cs_next[1+n_max]; */
+      /* cs_next[j], 1 <= j <= n, is the number of next column, which
+         has the same number of non-zeros (in the active rows) as j-th
+         column */
+      /* (end of working segment) */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      int *flag; /* int flag[1+n_max]; */
+      /* integer working array */
+      double *work; /* double work[1+n_max]; */
+      /* floating-point working array */
+      /*--------------------------------------------------------------*/
+      /* control parameters */
+      int new_sva;
+      /* new required size of the sparse vector area, in locations; set
+         automatically by the factorizing routine */
+      double piv_tol;
+      /* threshold pivoting tolerance, 0 < piv_tol < 1; element v[i,j]
+         of the active submatrix fits to be pivot if it satisfies to the
+         stability criterion |v[i,j]| >= piv_tol * max |v[i,*]|, i.e. if
+         it is not very small in the magnitude among other elements in
+         the same row; decreasing this parameter gives better sparsity
+         at the expense of numerical accuracy and vice versa */
+      int piv_lim;
+      /* maximal allowable number of pivot candidates to be considered;
+         if piv_lim pivot candidates have been considered, the pivoting
+         routine terminates the search with the best candidate found */
+      int suhl;
+      /* if this flag is set, the pivoting routine applies a heuristic
+         proposed by Uwe Suhl: if a column of the active submatrix has
+         no eligible pivot candidates (i.e. all its elements do not
+         satisfy to the stability criterion), the routine excludes it
+         from futher consideration until it becomes column singleton;
+         in many cases this allows reducing the time needed for pivot
+         searching */
+      double eps_tol;
+      /* epsilon tolerance; each element of the active submatrix, whose
+         magnitude is less than eps_tol, is replaced by exact zero */
+      double max_gro;
+      /* maximal allowable growth of elements of matrix V during all
+         the factorization process; if on some eliminaion step the ratio
+         big_v / max_a (see below) becomes greater than max_gro, matrix
+         A is considered as ill-conditioned (assuming that the pivoting
+         tolerance piv_tol has an appropriate value) */
+      /*--------------------------------------------------------------*/
+      /* some statistics */
+      int nnz_a;
+      /* the number of non-zeros in matrix A */
+      int nnz_f;
+      /* the number of non-zeros in matrix F (except diagonal elements,
+         which are not stored) */
+      int nnz_v;
+      /* the number of non-zeros in matrix V (except its pivot elements,
+         which are stored in a separate array) */
+      double max_a;
+      /* the largest magnitude of elements of matrix A */
+      double big_v;
+      /* the largest magnitude of elements of matrix V appeared in the
+         active submatrix during all the factorization process */
+      int rank;
+      /* estimated rank of matrix A */
+};
+
+/* return codes: */
+#define LUF_ESING    1  /* singular matrix */
+#define LUF_ECOND    2  /* ill-conditioned matrix */
+
+#define luf_create_it _glp_luf_create_it
+LUF *luf_create_it(void);
+/* create LU-factorization */
+
+#define luf_defrag_sva _glp_luf_defrag_sva
+void luf_defrag_sva(LUF *luf);
+/* defragment the sparse vector area */
+
+#define luf_enlarge_row _glp_luf_enlarge_row
+int luf_enlarge_row(LUF *luf, int i, int cap);
+/* enlarge row capacity */
+
+#define luf_enlarge_col _glp_luf_enlarge_col
+int luf_enlarge_col(LUF *luf, int j, int cap);
+/* enlarge column capacity */
+
+#define luf_factorize _glp_luf_factorize
+int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
+      int ind[], double val[]), void *info);
+/* compute LU-factorization */
+
+#define luf_f_solve _glp_luf_f_solve
+void luf_f_solve(LUF *luf, int tr, double x[]);
+/* solve system F*x = b or F'*x = b */
+
+#define luf_v_solve _glp_luf_v_solve
+void luf_v_solve(LUF *luf, int tr, double x[]);
+/* solve system V*x = b or V'*x = b */
+
+#define luf_a_solve _glp_luf_a_solve
+void luf_a_solve(LUF *luf, int tr, double x[]);
+/* solve system A*x = b or A'*x = b */
+
+#define luf_delete_it _glp_luf_delete_it
+void luf_delete_it(LUF *luf);
+/* delete LU-factorization */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glplux.c
===================================================================
--- deps/glpk/src/glplux.c	(revision 9)
+++ deps/glpk/src/glplux.c	(revision 9)
@@ -0,0 +1,1028 @@
+/* glplux.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glplux.h"
+#define xfault xerror
+#define dmp_create_poolx(size) dmp_create_pool()
+
+/*----------------------------------------------------------------------
+// lux_create - create LU-factorization.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// LUX *lux_create(int n);
+//
+// DESCRIPTION
+//
+// The routine lux_create creates LU-factorization data structure for
+// a matrix of the order n. Initially the factorization corresponds to
+// the unity matrix (F = V = P = Q = I, so A = I).
+//
+// RETURNS
+//
+// The routine returns a pointer to the created LU-factorization data
+// structure, which represents the unity matrix of the order n. */
+
+LUX *lux_create(int n)
+{     LUX *lux;
+      int k;
+      if (n < 1)
+         xfault("lux_create: n = %d; invalid parameter\n", n);
+      lux = xmalloc(sizeof(LUX));
+      lux->n = n;
+      lux->pool = dmp_create_poolx(sizeof(LUXELM));
+      lux->F_row = xcalloc(1+n, sizeof(LUXELM *));
+      lux->F_col = xcalloc(1+n, sizeof(LUXELM *));
+      lux->V_piv = xcalloc(1+n, sizeof(mpq_t));
+      lux->V_row = xcalloc(1+n, sizeof(LUXELM *));
+      lux->V_col = xcalloc(1+n, sizeof(LUXELM *));
+      lux->P_row = xcalloc(1+n, sizeof(int));
+      lux->P_col = xcalloc(1+n, sizeof(int));
+      lux->Q_row = xcalloc(1+n, sizeof(int));
+      lux->Q_col = xcalloc(1+n, sizeof(int));
+      for (k = 1; k <= n; k++)
+      {  lux->F_row[k] = lux->F_col[k] = NULL;
+         mpq_init(lux->V_piv[k]);
+         mpq_set_si(lux->V_piv[k], 1, 1);
+         lux->V_row[k] = lux->V_col[k] = NULL;
+         lux->P_row[k] = lux->P_col[k] = k;
+         lux->Q_row[k] = lux->Q_col[k] = k;
+      }
+      lux->rank = n;
+      return lux;
+}
+
+/*----------------------------------------------------------------------
+// initialize - initialize LU-factorization data structures.
+//
+// This routine initializes data structures for subsequent computing
+// the LU-factorization of a given matrix A, which is specified by the
+// formal routine col. On exit V = A and F = P = Q = I, where I is the
+// unity matrix. */
+
+static void initialize(LUX *lux, int (*col)(void *info, int j,
+      int ind[], mpq_t val[]), void *info, LUXWKA *wka)
+{     int n = lux->n;
+      DMP *pool = lux->pool;
+      LUXELM **F_row = lux->F_row;
+      LUXELM **F_col = lux->F_col;
+      mpq_t *V_piv = lux->V_piv;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *P_row = lux->P_row;
+      int *P_col = lux->P_col;
+      int *Q_row = lux->Q_row;
+      int *Q_col = lux->Q_col;
+      int *R_len = wka->R_len;
+      int *R_head = wka->R_head;
+      int *R_prev = wka->R_prev;
+      int *R_next = wka->R_next;
+      int *C_len = wka->C_len;
+      int *C_head = wka->C_head;
+      int *C_prev = wka->C_prev;
+      int *C_next = wka->C_next;
+      LUXELM *fij, *vij;
+      int i, j, k, len, *ind;
+      mpq_t *val;
+      /* F := I */
+      for (i = 1; i <= n; i++)
+      {  while (F_row[i] != NULL)
+         {  fij = F_row[i], F_row[i] = fij->r_next;
+            mpq_clear(fij->val);
+            dmp_free_atom(pool, fij, sizeof(LUXELM));
+         }
+      }
+      for (j = 1; j <= n; j++) F_col[j] = NULL;
+      /* V := 0 */
+      for (k = 1; k <= n; k++) mpq_set_si(V_piv[k], 0, 1);
+      for (i = 1; i <= n; i++)
+      {  while (V_row[i] != NULL)
+         {  vij = V_row[i], V_row[i] = vij->r_next;
+            mpq_clear(vij->val);
+            dmp_free_atom(pool, vij, sizeof(LUXELM));
+         }
+      }
+      for (j = 1; j <= n; j++) V_col[j] = NULL;
+      /* V := A */
+      ind = xcalloc(1+n, sizeof(int));
+      val = xcalloc(1+n, sizeof(mpq_t));
+      for (k = 1; k <= n; k++) mpq_init(val[k]);
+      for (j = 1; j <= n; j++)
+      {  /* obtain j-th column of matrix A */
+         len = col(info, j, ind, val);
+         if (!(0 <= len && len <= n))
+            xfault("lux_decomp: j = %d: len = %d; invalid column length"
+               "\n", j, len);
+         /* copy elements of j-th column to matrix V */
+         for (k = 1; k <= len; k++)
+         {  /* get row index of a[i,j] */
+            i = ind[k];
+            if (!(1 <= i && i <= n))
+               xfault("lux_decomp: j = %d: i = %d; row index out of ran"
+                  "ge\n", j, i);
+            /* check for duplicate indices */
+            if (V_row[i] != NULL && V_row[i]->j == j)
+               xfault("lux_decomp: j = %d: i = %d; duplicate row indice"
+                  "s not allowed\n", j, i);
+            /* check for zero value */
+            if (mpq_sgn(val[k]) == 0)
+               xfault("lux_decomp: j = %d: i = %d; zero elements not al"
+                  "lowed\n", j, i);
+            /* add new element v[i,j] = a[i,j] to V */
+            vij = dmp_get_atom(pool, sizeof(LUXELM));
+            vij->i = i, vij->j = j;
+            mpq_init(vij->val);
+            mpq_set(vij->val, val[k]);
+            vij->r_prev = NULL;
+            vij->r_next = V_row[i];
+            vij->c_prev = NULL;
+            vij->c_next = V_col[j];
+            if (vij->r_next != NULL) vij->r_next->r_prev = vij;
+            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+            V_row[i] = V_col[j] = vij;
+         }
+      }
+      xfree(ind);
+      for (k = 1; k <= n; k++) mpq_clear(val[k]);
+      xfree(val);
+      /* P := Q := I */
+      for (k = 1; k <= n; k++)
+         P_row[k] = P_col[k] = Q_row[k] = Q_col[k] = k;
+      /* the rank of A and V is not determined yet */
+      lux->rank = -1;
+      /* initially the entire matrix V is active */
+      /* determine its row lengths */
+      for (i = 1; i <= n; i++)
+      {  len = 0;
+         for (vij = V_row[i]; vij != NULL; vij = vij->r_next) len++;
+         R_len[i] = len;
+      }
+      /* build linked lists of active rows */
+      for (len = 0; len <= n; len++) R_head[len] = 0;
+      for (i = 1; i <= n; i++)
+      {  len = R_len[i];
+         R_prev[i] = 0;
+         R_next[i] = R_head[len];
+         if (R_next[i] != 0) R_prev[R_next[i]] = i;
+         R_head[len] = i;
+      }
+      /* determine its column lengths */
+      for (j = 1; j <= n; j++)
+      {  len = 0;
+         for (vij = V_col[j]; vij != NULL; vij = vij->c_next) len++;
+         C_len[j] = len;
+      }
+      /* build linked lists of active columns */
+      for (len = 0; len <= n; len++) C_head[len] = 0;
+      for (j = 1; j <= n; j++)
+      {  len = C_len[j];
+         C_prev[j] = 0;
+         C_next[j] = C_head[len];
+         if (C_next[j] != 0) C_prev[C_next[j]] = j;
+         C_head[len] = j;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// find_pivot - choose a pivot element.
+//
+// This routine chooses a pivot element v[p,q] in the active submatrix
+// of matrix U = P*V*Q.
+//
+// It is assumed that on entry the matrix U has the following partially
+// triangularized form:
+//
+//       1       k         n
+//    1  x x x x x x x x x x
+//       . x x x x x x x x x
+//       . . x x x x x x x x
+//       . . . x x x x x x x
+//    k  . . . . * * * * * *
+//       . . . . * * * * * *
+//       . . . . * * * * * *
+//       . . . . * * * * * *
+//       . . . . * * * * * *
+//    n  . . . . * * * * * *
+//
+// where rows and columns k, k+1, ..., n belong to the active submatrix
+// (elements of the active submatrix are marked by '*').
+//
+// Since the matrix U = P*V*Q is not stored, the routine works with the
+// matrix V. It is assumed that the row-wise representation corresponds
+// to the matrix V, but the column-wise representation corresponds to
+// the active submatrix of the matrix V, i.e. elements of the matrix V,
+// which does not belong to the active submatrix, are missing from the
+// column linked lists. It is also assumed that each active row of the
+// matrix V is in the set R[len], where len is number of non-zeros in
+// the row, and each active column of the matrix V is in the set C[len],
+// where len is number of non-zeros in the column (in the latter case
+// only elements of the active submatrix are counted; such elements are
+// marked by '*' on the figure above).
+//
+// Due to exact arithmetic any non-zero element of the active submatrix
+// can be chosen as a pivot. However, to keep sparsity of the matrix V
+// the routine uses Markowitz strategy, trying to choose such element
+// v[p,q], which has smallest Markowitz cost (nr[p]-1) * (nc[q]-1),
+// where nr[p] and nc[q] are the number of non-zero elements, resp., in
+// p-th row and in q-th column of the active submatrix.
+//
+// In order to reduce the search, i.e. not to walk through all elements
+// of the active submatrix, the routine exploits a technique proposed by
+// I.Duff. This technique is based on using the sets R[len] and C[len]
+// of active rows and columns.
+//
+// On exit the routine returns a pointer to a pivot v[p,q] chosen, or
+// NULL, if the active submatrix is empty. */
+
+static LUXELM *find_pivot(LUX *lux, LUXWKA *wka)
+{     int n = lux->n;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *R_len = wka->R_len;
+      int *R_head = wka->R_head;
+      int *R_next = wka->R_next;
+      int *C_len = wka->C_len;
+      int *C_head = wka->C_head;
+      int *C_next = wka->C_next;
+      LUXELM *piv, *some, *vij;
+      int i, j, len, min_len, ncand, piv_lim = 5;
+      double best, cost;
+      /* nothing is chosen so far */
+      piv = NULL, best = DBL_MAX, ncand = 0;
+      /* if in the active submatrix there is a column that has the only
+         non-zero (column singleton), choose it as a pivot */
+      j = C_head[1];
+      if (j != 0)
+      {  xassert(C_len[j] == 1);
+         piv = V_col[j];
+         xassert(piv != NULL && piv->c_next == NULL);
+         goto done;
+      }
+      /* if in the active submatrix there is a row that has the only
+         non-zero (row singleton), choose it as a pivot */
+      i = R_head[1];
+      if (i != 0)
+      {  xassert(R_len[i] == 1);
+         piv = V_row[i];
+         xassert(piv != NULL && piv->r_next == NULL);
+         goto done;
+      }
+      /* there are no singletons in the active submatrix; walk through
+         other non-empty rows and columns */
+      for (len = 2; len <= n; len++)
+      {  /* consider active columns having len non-zeros */
+         for (j = C_head[len]; j != 0; j = C_next[j])
+         {  /* j-th column has len non-zeros */
+            /* find an element in the row of minimal length */
+            some = NULL, min_len = INT_MAX;
+            for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
+            {  if (min_len > R_len[vij->i])
+                  some = vij, min_len = R_len[vij->i];
+               /* if Markowitz cost of this element is not greater than
+                  (len-1)**2, it can be chosen right now; this heuristic
+                  reduces the search and works well in many cases */
+               if (min_len <= len)
+               {  piv = some;
+                  goto done;
+               }
+            }
+            /* j-th column has been scanned */
+            /* the minimal element found is a next pivot candidate */
+            xassert(some != NULL);
+            ncand++;
+            /* compute its Markowitz cost */
+            cost = (double)(min_len - 1) * (double)(len - 1);
+            /* choose between the current candidate and this element */
+            if (cost < best) piv = some, best = cost;
+            /* if piv_lim candidates have been considered, there is a
+               doubt that a much better candidate exists; therefore it
+               is the time to terminate the search */
+            if (ncand == piv_lim) goto done;
+         }
+         /* now consider active rows having len non-zeros */
+         for (i = R_head[len]; i != 0; i = R_next[i])
+         {  /* i-th row has len non-zeros */
+            /* find an element in the column of minimal length */
+            some = NULL, min_len = INT_MAX;
+            for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+            {  if (min_len > C_len[vij->j])
+                  some = vij, min_len = C_len[vij->j];
+               /* if Markowitz cost of this element is not greater than
+                  (len-1)**2, it can be chosen right now; this heuristic
+                  reduces the search and works well in many cases */
+               if (min_len <= len)
+               {  piv = some;
+                  goto done;
+               }
+            }
+            /* i-th row has been scanned */
+            /* the minimal element found is a next pivot candidate */
+            xassert(some != NULL);
+            ncand++;
+            /* compute its Markowitz cost */
+            cost = (double)(len - 1) * (double)(min_len - 1);
+            /* choose between the current candidate and this element */
+            if (cost < best) piv = some, best = cost;
+            /* if piv_lim candidates have been considered, there is a
+               doubt that a much better candidate exists; therefore it
+               is the time to terminate the search */
+            if (ncand == piv_lim) goto done;
+         }
+      }
+done: /* bring the pivot v[p,q] to the factorizing routine */
+      return piv;
+}
+
+/*----------------------------------------------------------------------
+// eliminate - perform gaussian elimination.
+//
+// This routine performs elementary gaussian transformations in order
+// to eliminate subdiagonal elements in the k-th column of the matrix
+// U = P*V*Q using the pivot element u[k,k], where k is the number of
+// the current elimination step.
+//
+// The parameter piv specifies the pivot element v[p,q] = u[k,k].
+//
+// Each time when the routine applies the elementary transformation to
+// a non-pivot row of the matrix V, it stores the corresponding element
+// to the matrix F in order to keep the main equality A = F*V.
+//
+// The routine assumes that on entry the matrices L = P*F*inv(P) and
+// U = P*V*Q are the following:
+//
+//       1       k                  1       k         n
+//    1  1 . . . . . . . . .     1  x x x x x x x x x x
+//       x 1 . . . . . . . .        . x x x x x x x x x
+//       x x 1 . . . . . . .        . . x x x x x x x x
+//       x x x 1 . . . . . .        . . . x x x x x x x
+//    k  x x x x 1 . . . . .     k  . . . . * * * * * *
+//       x x x x _ 1 . . . .        . . . . # * * * * *
+//       x x x x _ . 1 . . .        . . . . # * * * * *
+//       x x x x _ . . 1 . .        . . . . # * * * * *
+//       x x x x _ . . . 1 .        . . . . # * * * * *
+//    n  x x x x _ . . . . 1     n  . . . . # * * * * *
+//
+//            matrix L                   matrix U
+//
+// where rows and columns of the matrix U with numbers k, k+1, ..., n
+// form the active submatrix (eliminated elements are marked by '#' and
+// other elements of the active submatrix are marked by '*'). Note that
+// each eliminated non-zero element u[i,k] of the matrix U gives the
+// corresponding element l[i,k] of the matrix L (marked by '_').
+//
+// Actually all operations are performed on the matrix V. Should note
+// that the row-wise representation corresponds to the matrix V, but the
+// column-wise representation corresponds to the active submatrix of the
+// matrix V, i.e. elements of the matrix V, which doesn't belong to the
+// active submatrix, are missing from the column linked lists.
+//
+// Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
+// elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
+// the following elementary gaussian transformations:
+//
+//    (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
+//
+// where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
+//
+// Additionally, in order to keep the main equality A = F*V, each time
+// when the routine applies the transformation to i-th row of the matrix
+// V, it also adds f[i,p] as a new element to the matrix F.
+//
+// IMPORTANT: On entry the working arrays flag and work should contain
+// zeros. This status is provided by the routine on exit. */
+
+static void eliminate(LUX *lux, LUXWKA *wka, LUXELM *piv, int flag[],
+      mpq_t work[])
+{     DMP *pool = lux->pool;
+      LUXELM **F_row = lux->F_row;
+      LUXELM **F_col = lux->F_col;
+      mpq_t *V_piv = lux->V_piv;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *R_len = wka->R_len;
+      int *R_head = wka->R_head;
+      int *R_prev = wka->R_prev;
+      int *R_next = wka->R_next;
+      int *C_len = wka->C_len;
+      int *C_head = wka->C_head;
+      int *C_prev = wka->C_prev;
+      int *C_next = wka->C_next;
+      LUXELM *fip, *vij, *vpj, *viq, *next;
+      mpq_t temp;
+      int i, j, p, q;
+      mpq_init(temp);
+      /* determine row and column indices of the pivot v[p,q] */
+      xassert(piv != NULL);
+      p = piv->i, q = piv->j;
+      /* remove p-th (pivot) row from the active set; it will never
+         return there */
+      if (R_prev[p] == 0)
+         R_head[R_len[p]] = R_next[p];
+      else
+         R_next[R_prev[p]] = R_next[p];
+      if (R_next[p] == 0)
+         ;
+      else
+         R_prev[R_next[p]] = R_prev[p];
+      /* remove q-th (pivot) column from the active set; it will never
+         return there */
+      if (C_prev[q] == 0)
+         C_head[C_len[q]] = C_next[q];
+      else
+         C_next[C_prev[q]] = C_next[q];
+      if (C_next[q] == 0)
+         ;
+      else
+         C_prev[C_next[q]] = C_prev[q];
+      /* store the pivot value in a separate array */
+      mpq_set(V_piv[p], piv->val);
+      /* remove the pivot from p-th row */
+      if (piv->r_prev == NULL)
+         V_row[p] = piv->r_next;
+      else
+         piv->r_prev->r_next = piv->r_next;
+      if (piv->r_next == NULL)
+         ;
+      else
+         piv->r_next->r_prev = piv->r_prev;
+      R_len[p]--;
+      /* remove the pivot from q-th column */
+      if (piv->c_prev == NULL)
+         V_col[q] = piv->c_next;
+      else
+         piv->c_prev->c_next = piv->c_next;
+      if (piv->c_next == NULL)
+         ;
+      else
+         piv->c_next->c_prev = piv->c_prev;
+      C_len[q]--;
+      /* free the space occupied by the pivot */
+      mpq_clear(piv->val);
+      dmp_free_atom(pool, piv, sizeof(LUXELM));
+      /* walk through p-th (pivot) row, which already does not contain
+         the pivot v[p,q], and do the following... */
+      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+      {  /* get column index of v[p,j] */
+         j = vpj->j;
+         /* store v[p,j] in the working array */
+         flag[j] = 1;
+         mpq_set(work[j], vpj->val);
+         /* remove j-th column from the active set; it will return there
+            later with a new length */
+         if (C_prev[j] == 0)
+            C_head[C_len[j]] = C_next[j];
+         else
+            C_next[C_prev[j]] = C_next[j];
+         if (C_next[j] == 0)
+            ;
+         else
+            C_prev[C_next[j]] = C_prev[j];
+         /* v[p,j] leaves the active submatrix, so remove it from j-th
+            column; however, v[p,j] is kept in p-th row */
+         if (vpj->c_prev == NULL)
+            V_col[j] = vpj->c_next;
+         else
+            vpj->c_prev->c_next = vpj->c_next;
+         if (vpj->c_next == NULL)
+            ;
+         else
+            vpj->c_next->c_prev = vpj->c_prev;
+         C_len[j]--;
+      }
+      /* now walk through q-th (pivot) column, which already does not
+         contain the pivot v[p,q], and perform gaussian elimination */
+      while (V_col[q] != NULL)
+      {  /* element v[i,q] has to be eliminated */
+         viq = V_col[q];
+         /* get row index of v[i,q] */
+         i = viq->i;
+         /* remove i-th row from the active set; later it will return
+            there with a new length */
+         if (R_prev[i] == 0)
+            R_head[R_len[i]] = R_next[i];
+         else
+            R_next[R_prev[i]] = R_next[i];
+         if (R_next[i] == 0)
+            ;
+         else
+            R_prev[R_next[i]] = R_prev[i];
+         /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] and
+            store it in the matrix F */
+         fip = dmp_get_atom(pool, sizeof(LUXELM));
+         fip->i = i, fip->j = p;
+         mpq_init(fip->val);
+         mpq_div(fip->val, viq->val, V_piv[p]);
+         fip->r_prev = NULL;
+         fip->r_next = F_row[i];
+         fip->c_prev = NULL;
+         fip->c_next = F_col[p];
+         if (fip->r_next != NULL) fip->r_next->r_prev = fip;
+         if (fip->c_next != NULL) fip->c_next->c_prev = fip;
+         F_row[i] = F_col[p] = fip;
+         /* v[i,q] has to be eliminated, so remove it from i-th row */
+         if (viq->r_prev == NULL)
+            V_row[i] = viq->r_next;
+         else
+            viq->r_prev->r_next = viq->r_next;
+         if (viq->r_next == NULL)
+            ;
+         else
+            viq->r_next->r_prev = viq->r_prev;
+         R_len[i]--;
+         /* and also from q-th column */
+         V_col[q] = viq->c_next;
+         C_len[q]--;
+         /* free the space occupied by v[i,q] */
+         mpq_clear(viq->val);
+         dmp_free_atom(pool, viq, sizeof(LUXELM));
+         /* perform gaussian transformation:
+            (i-th row) := (i-th row) - f[i,p] * (p-th row)
+            note that now p-th row, which is in the working array,
+            does not contain the pivot v[p,q], and i-th row does not
+            contain the element v[i,q] to be eliminated */
+         /* walk through i-th row and transform existing non-zero
+            elements */
+         for (vij = V_row[i]; vij != NULL; vij = next)
+         {  next = vij->r_next;
+            /* get column index of v[i,j] */
+            j = vij->j;
+            /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
+            if (flag[j])
+            {  /* v[p,j] != 0 */
+               flag[j] = 0;
+               mpq_mul(temp, fip->val, work[j]);
+               mpq_sub(vij->val, vij->val, temp);
+               if (mpq_sgn(vij->val) == 0)
+               {  /* new v[i,j] is zero, so remove it from the active
+                     submatrix */
+                  /* remove v[i,j] from i-th row */
+                  if (vij->r_prev == NULL)
+                     V_row[i] = vij->r_next;
+                  else
+                     vij->r_prev->r_next = vij->r_next;
+                  if (vij->r_next == NULL)
+                     ;
+                  else
+                     vij->r_next->r_prev = vij->r_prev;
+                  R_len[i]--;
+                  /* remove v[i,j] from j-th column */
+                  if (vij->c_prev == NULL)
+                     V_col[j] = vij->c_next;
+                  else
+                     vij->c_prev->c_next = vij->c_next;
+                  if (vij->c_next == NULL)
+                     ;
+                  else
+                     vij->c_next->c_prev = vij->c_prev;
+                  C_len[j]--;
+                  /* free the space occupied by v[i,j] */
+                  mpq_clear(vij->val);
+                  dmp_free_atom(pool, vij, sizeof(LUXELM));
+               }
+            }
+         }
+         /* now flag is the pattern of the set v[p,*] \ v[i,*] */
+         /* walk through p-th (pivot) row and create new elements in
+            i-th row, which appear due to fill-in */
+         for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+         {  j = vpj->j;
+            if (flag[j])
+            {  /* create new non-zero v[i,j] = 0 - f[i,p] * v[p,j] and
+                  add it to i-th row and j-th column */
+               vij = dmp_get_atom(pool, sizeof(LUXELM));
+               vij->i = i, vij->j = j;
+               mpq_init(vij->val);
+               mpq_mul(vij->val, fip->val, work[j]);
+               mpq_neg(vij->val, vij->val);
+               vij->r_prev = NULL;
+               vij->r_next = V_row[i];
+               vij->c_prev = NULL;
+               vij->c_next = V_col[j];
+               if (vij->r_next != NULL) vij->r_next->r_prev = vij;
+               if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+               V_row[i] = V_col[j] = vij;
+               R_len[i]++, C_len[j]++;
+            }
+            else
+            {  /* there is no fill-in, because v[i,j] already exists in
+                  i-th row; restore the flag, which was reset before */
+               flag[j] = 1;
+            }
+         }
+         /* now i-th row has been completely transformed and can return
+            to the active set with a new length */
+         R_prev[i] = 0;
+         R_next[i] = R_head[R_len[i]];
+         if (R_next[i] != 0) R_prev[R_next[i]] = i;
+         R_head[R_len[i]] = i;
+      }
+      /* at this point q-th (pivot) column must be empty */
+      xassert(C_len[q] == 0);
+      /* walk through p-th (pivot) row again and do the following... */
+      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
+      {  /* get column index of v[p,j] */
+         j = vpj->j;
+         /* erase v[p,j] from the working array */
+         flag[j] = 0;
+         mpq_set_si(work[j], 0, 1);
+         /* now j-th column has been completely transformed, so it can
+            return to the active list with a new length */
+         C_prev[j] = 0;
+         C_next[j] = C_head[C_len[j]];
+         if (C_next[j] != 0) C_prev[C_next[j]] = j;
+         C_head[C_len[j]] = j;
+      }
+      mpq_clear(temp);
+      /* return to the factorizing routine */
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_decomp - compute LU-factorization.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+//    mpq_t val[]), void *info);
+//
+// DESCRIPTION
+//
+// The routine lux_decomp computes LU-factorization of a given square
+// matrix A.
+//
+// The parameter lux specifies LU-factorization data structure built by
+// means of the routine lux_create.
+//
+// The formal routine col specifies the original matrix A. In order to
+// obtain j-th column of the matrix A the routine lux_decomp calls the
+// routine col with the parameter j (1 <= j <= n, where n is the order
+// of A). In response the routine col should store row indices and
+// numerical values of non-zero elements of j-th column of A to the
+// locations ind[1], ..., ind[len] and val[1], ..., val[len], resp.,
+// where len is the number of non-zeros in j-th column, which should be
+// returned on exit. Neiter zero nor duplicate elements are allowed.
+//
+// The parameter info is a transit pointer passed to the formal routine
+// col; it can be used for various purposes.
+//
+// RETURNS
+//
+// The routine lux_decomp returns the singularity flag. Zero flag means
+// that the original matrix A is non-singular while non-zero flag means
+// that A is (exactly!) singular.
+//
+// Note that LU-factorization is valid in both cases, however, in case
+// of singularity some rows of the matrix V (including pivot elements)
+// will be empty.
+//
+// REPAIRING SINGULAR MATRIX
+//
+// If the routine lux_decomp returns non-zero flag, it provides all
+// necessary information that can be used for "repairing" the matrix A,
+// where "repairing" means replacing linearly dependent columns of the
+// matrix A by appropriate columns of the unity matrix. This feature is
+// needed when the routine lux_decomp is used for reinverting the basis
+// matrix within the simplex method procedure.
+//
+// On exit linearly dependent columns of the matrix U have the numbers
+// rank+1, rank+2, ..., n, where rank is the exact rank of the matrix A
+// stored by the routine to the member lux->rank. The correspondence
+// between columns of A and U is the same as between columns of V and U.
+// Thus, linearly dependent columns of the matrix A have the numbers
+// Q_col[rank+1], Q_col[rank+2], ..., Q_col[n], where Q_col is an array
+// representing the permutation matrix Q in column-like format. It is
+// understood that each j-th linearly dependent column of the matrix U
+// should be replaced by the unity vector, where all elements are zero
+// except the unity diagonal element u[j,j]. On the other hand j-th row
+// of the matrix U corresponds to the row of the matrix V (and therefore
+// of the matrix A) with the number P_row[j], where P_row is an array
+// representing the permutation matrix P in row-like format. Thus, each
+// j-th linearly dependent column of the matrix U should be replaced by
+// a column of the unity matrix with the number P_row[j].
+//
+// The code that repairs the matrix A may look like follows:
+//
+//    for (j = rank+1; j <= n; j++)
+//    {  replace column Q_col[j] of the matrix A by column P_row[j] of
+//       the unity matrix;
+//    }
+//
+// where rank, P_row, and Q_col are members of the structure LUX. */
+
+int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+      mpq_t val[]), void *info)
+{     int n = lux->n;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *P_row = lux->P_row;
+      int *P_col = lux->P_col;
+      int *Q_row = lux->Q_row;
+      int *Q_col = lux->Q_col;
+      LUXELM *piv, *vij;
+      LUXWKA *wka;
+      int i, j, k, p, q, t, *flag;
+      mpq_t *work;
+      /* allocate working area */
+      wka = xmalloc(sizeof(LUXWKA));
+      wka->R_len = xcalloc(1+n, sizeof(int));
+      wka->R_head = xcalloc(1+n, sizeof(int));
+      wka->R_prev = xcalloc(1+n, sizeof(int));
+      wka->R_next = xcalloc(1+n, sizeof(int));
+      wka->C_len = xcalloc(1+n, sizeof(int));
+      wka->C_head = xcalloc(1+n, sizeof(int));
+      wka->C_prev = xcalloc(1+n, sizeof(int));
+      wka->C_next = xcalloc(1+n, sizeof(int));
+      /* initialize LU-factorization data structures */
+      initialize(lux, col, info, wka);
+      /* allocate working arrays */
+      flag = xcalloc(1+n, sizeof(int));
+      work = xcalloc(1+n, sizeof(mpq_t));
+      for (k = 1; k <= n; k++)
+      {  flag[k] = 0;
+         mpq_init(work[k]);
+      }
+      /* main elimination loop */
+      for (k = 1; k <= n; k++)
+      {  /* choose a pivot element v[p,q] */
+         piv = find_pivot(lux, wka);
+         if (piv == NULL)
+         {  /* no pivot can be chosen, because the active submatrix is
+               empty */
+            break;
+         }
+         /* determine row and column indices of the pivot element */
+         p = piv->i, q = piv->j;
+         /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
+            rows and k-th and j'-th columns of the matrix U = P*V*Q to
+            move the element u[i',j'] to the position u[k,k] */
+         i = P_col[p], j = Q_row[q];
+         xassert(k <= i && i <= n && k <= j && j <= n);
+         /* permute k-th and i-th rows of the matrix U */
+         t = P_row[k];
+         P_row[i] = t, P_col[t] = i;
+         P_row[k] = p, P_col[p] = k;
+         /* permute k-th and j-th columns of the matrix U */
+         t = Q_col[k];
+         Q_col[j] = t, Q_row[t] = j;
+         Q_col[k] = q, Q_row[q] = k;
+         /* eliminate subdiagonal elements of k-th column of the matrix
+            U = P*V*Q using the pivot element u[k,k] = v[p,q] */
+         eliminate(lux, wka, piv, flag, work);
+      }
+      /* determine the rank of A (and V) */
+      lux->rank = k - 1;
+      /* free working arrays */
+      xfree(flag);
+      for (k = 1; k <= n; k++) mpq_clear(work[k]);
+      xfree(work);
+      /* build column lists of the matrix V using its row lists */
+      for (j = 1; j <= n; j++)
+         xassert(V_col[j] == NULL);
+      for (i = 1; i <= n; i++)
+      {  for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+         {  j = vij->j;
+            vij->c_prev = NULL;
+            vij->c_next = V_col[j];
+            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
+            V_col[j] = vij;
+         }
+      }
+      /* free working area */
+      xfree(wka->R_len);
+      xfree(wka->R_head);
+      xfree(wka->R_prev);
+      xfree(wka->R_next);
+      xfree(wka->C_len);
+      xfree(wka->C_head);
+      xfree(wka->C_prev);
+      xfree(wka->C_next);
+      xfree(wka);
+      /* return to the calling program */
+      return (lux->rank < n);
+}
+
+/*----------------------------------------------------------------------
+// lux_f_solve - solve system F*x = b or F'*x = b.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
+//
+// DESCRIPTION
+//
+// The routine lux_f_solve solves either the system F*x = b (if the
+// flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
+// where the matrix F is a component of LU-factorization specified by
+// the parameter lux, F' is a matrix transposed to F.
+//
+// On entry the array x should contain elements of the right-hand side
+// vector b in locations x[1], ..., x[n], where n is the order of the
+// matrix F. On exit this array will contain elements of the solution
+// vector x in the same locations. */
+
+void lux_f_solve(LUX *lux, int tr, mpq_t x[])
+{     int n = lux->n;
+      LUXELM **F_row = lux->F_row;
+      LUXELM **F_col = lux->F_col;
+      int *P_row = lux->P_row;
+      LUXELM *fik, *fkj;
+      int i, j, k;
+      mpq_t temp;
+      mpq_init(temp);
+      if (!tr)
+      {  /* solve the system F*x = b */
+         for (j = 1; j <= n; j++)
+         {  k = P_row[j];
+            if (mpq_sgn(x[k]) != 0)
+            {  for (fik = F_col[k]; fik != NULL; fik = fik->c_next)
+               {  mpq_mul(temp, fik->val, x[k]);
+                  mpq_sub(x[fik->i], x[fik->i], temp);
+               }
+            }
+         }
+      }
+      else
+      {  /* solve the system F'*x = b */
+         for (i = n; i >= 1; i--)
+         {  k = P_row[i];
+            if (mpq_sgn(x[k]) != 0)
+            {  for (fkj = F_row[k]; fkj != NULL; fkj = fkj->r_next)
+               {  mpq_mul(temp, fkj->val, x[k]);
+                  mpq_sub(x[fkj->j], x[fkj->j], temp);
+               }
+            }
+         }
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_v_solve - solve system V*x = b or V'*x = b.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_v_solve(LUX *lux, int tr, double x[]);
+//
+// DESCRIPTION
+//
+// The routine lux_v_solve solves either the system V*x = b (if the
+// flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
+// where the matrix V is a component of LU-factorization specified by
+// the parameter lux, V' is a matrix transposed to V.
+//
+// On entry the array x should contain elements of the right-hand side
+// vector b in locations x[1], ..., x[n], where n is the order of the
+// matrix V. On exit this array will contain elements of the solution
+// vector x in the same locations. */
+
+void lux_v_solve(LUX *lux, int tr, mpq_t x[])
+{     int n = lux->n;
+      mpq_t *V_piv = lux->V_piv;
+      LUXELM **V_row = lux->V_row;
+      LUXELM **V_col = lux->V_col;
+      int *P_row = lux->P_row;
+      int *Q_col = lux->Q_col;
+      LUXELM *vij;
+      int i, j, k;
+      mpq_t *b, temp;
+      b = xcalloc(1+n, sizeof(mpq_t));
+      for (k = 1; k <= n; k++)
+         mpq_init(b[k]), mpq_set(b[k], x[k]), mpq_set_si(x[k], 0, 1);
+      mpq_init(temp);
+      if (!tr)
+      {  /* solve the system V*x = b */
+         for (k = n; k >= 1; k--)
+         {  i = P_row[k], j = Q_col[k];
+            if (mpq_sgn(b[i]) != 0)
+            {  mpq_set(x[j], b[i]);
+               mpq_div(x[j], x[j], V_piv[i]);
+               for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
+               {  mpq_mul(temp, vij->val, x[j]);
+                  mpq_sub(b[vij->i], b[vij->i], temp);
+               }
+            }
+         }
+      }
+      else
+      {  /* solve the system V'*x = b */
+         for (k = 1; k <= n; k++)
+         {  i = P_row[k], j = Q_col[k];
+            if (mpq_sgn(b[j]) != 0)
+            {  mpq_set(x[i], b[j]);
+               mpq_div(x[i], x[i], V_piv[i]);
+               for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
+               {  mpq_mul(temp, vij->val, x[i]);
+                  mpq_sub(b[vij->j], b[vij->j], temp);
+               }
+            }
+         }
+      }
+      for (k = 1; k <= n; k++) mpq_clear(b[k]);
+      mpq_clear(temp);
+      xfree(b);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_solve - solve system A*x = b or A'*x = b.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_solve(LUX *lux, int tr, mpq_t x[]);
+//
+// DESCRIPTION
+//
+// The routine lux_solve solves either the system A*x = b (if the flag
+// tr is zero) or the system A'*x = b (if the flag tr is non-zero),
+// where the parameter lux specifies LU-factorization of the matrix A,
+// A' is a matrix transposed to A.
+//
+// On entry the array x should contain elements of the right-hand side
+// vector b in locations x[1], ..., x[n], where n is the order of the
+// matrix A. On exit this array will contain elements of the solution
+// vector x in the same locations. */
+
+void lux_solve(LUX *lux, int tr, mpq_t x[])
+{     if (lux->rank < lux->n)
+         xfault("lux_solve: LU-factorization has incomplete rank\n");
+      if (!tr)
+      {  /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
+         lux_f_solve(lux, 0, x);
+         lux_v_solve(lux, 0, x);
+      }
+      else
+      {  /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
+         lux_v_solve(lux, 1, x);
+         lux_f_solve(lux, 1, x);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// lux_delete - delete LU-factorization.
+//
+// SYNOPSIS
+//
+// #include "glplux.h"
+// void lux_delete(LUX *lux);
+//
+// DESCRIPTION
+//
+// The routine lux_delete deletes LU-factorization data structure,
+// which the parameter lux points to, freeing all the memory allocated
+// to this object. */
+
+void lux_delete(LUX *lux)
+{     int n = lux->n;
+      LUXELM *fij, *vij;
+      int i;
+      for (i = 1; i <= n; i++)
+      {  for (fij = lux->F_row[i]; fij != NULL; fij = fij->r_next)
+            mpq_clear(fij->val);
+         mpq_clear(lux->V_piv[i]);
+         for (vij = lux->V_row[i]; vij != NULL; vij = vij->r_next)
+            mpq_clear(vij->val);
+      }
+      dmp_delete_pool(lux->pool);
+      xfree(lux->F_row);
+      xfree(lux->F_col);
+      xfree(lux->V_piv);
+      xfree(lux->V_row);
+      xfree(lux->V_col);
+      xfree(lux->P_row);
+      xfree(lux->P_col);
+      xfree(lux->Q_row);
+      xfree(lux->Q_col);
+      xfree(lux);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glplux.h
===================================================================
--- deps/glpk/src/glplux.h	(revision 9)
+++ deps/glpk/src/glplux.h	(revision 9)
@@ -0,0 +1,221 @@
+/* glplux.h (LU-factorization, bignum arithmetic) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPLUX_H
+#define GLPLUX_H
+
+#include "glpdmp.h"
+#include "glpgmp.h"
+
+/*----------------------------------------------------------------------
+// The structure LUX defines LU-factorization of a square matrix A,
+// which is the following quartet:
+//
+//    [A] = (F, V, P, Q),                                            (1)
+//
+// where F and V are such matrices that
+//
+//    A = F * V,                                                     (2)
+//
+// and P and Q are such permutation matrices that the matrix
+//
+//    L = P * F * inv(P)                                             (3)
+//
+// is lower triangular with unity diagonal, and the matrix
+//
+//    U = P * V * Q                                                  (4)
+//
+// is upper triangular. All the matrices have the order n.
+//
+// The matrices F and V are stored in row/column-wise sparse format as
+// row and column linked lists of non-zero elements. Unity elements on
+// the main diagonal of the matrix F are not stored. Pivot elements of
+// the matrix V (that correspond to diagonal elements of the matrix U)
+// are also missing from the row and column lists and stored separately
+// in an ordinary array.
+//
+// The permutation matrices P and Q are stored as ordinary arrays using
+// both row- and column-like formats.
+//
+// The matrices L and U being completely defined by the matrices F, V,
+// P, and Q are not stored explicitly.
+//
+// It is easy to show that the factorization (1)-(3) is some version of
+// LU-factorization. Indeed, from (3) and (4) it follows that:
+//
+//    F = inv(P) * L * P,
+//
+//    V = inv(P) * U * inv(Q),
+//
+// and substitution into (2) gives:
+//
+//    A = F * V = inv(P) * L * U * inv(Q).
+//
+// For more details see the program documentation. */
+
+typedef struct LUX LUX;
+typedef struct LUXELM LUXELM;
+typedef struct LUXWKA LUXWKA;
+
+struct LUX
+{     /* LU-factorization of a square matrix */
+      int n;
+      /* the order of matrices A, F, V, P, Q */
+      DMP *pool;
+      /* memory pool for elements of matrices F and V */
+      LUXELM **F_row; /* LUXELM *F_row[1+n]; */
+      /* F_row[0] is not used;
+         F_row[i], 1 <= i <= n, is a pointer to the list of elements in
+         i-th row of matrix F (diagonal elements are not stored) */
+      LUXELM **F_col; /* LUXELM *F_col[1+n]; */
+      /* F_col[0] is not used;
+         F_col[j], 1 <= j <= n, is a pointer to the list of elements in
+         j-th column of matrix F (diagonal elements are not stored) */
+      mpq_t *V_piv; /* mpq_t V_piv[1+n]; */
+      /* V_piv[0] is not used;
+         V_piv[p], 1 <= p <= n, is a pivot element v[p,q] corresponding
+         to a diagonal element u[k,k] of matrix U = P*V*Q (used on k-th
+         elimination step, k = 1, 2, ..., n) */
+      LUXELM **V_row; /* LUXELM *V_row[1+n]; */
+      /* V_row[0] is not used;
+         V_row[i], 1 <= i <= n, is a pointer to the list of elements in
+         i-th row of matrix V (except pivot elements) */
+      LUXELM **V_col; /* LUXELM *V_col[1+n]; */
+      /* V_col[0] is not used;
+         V_col[j], 1 <= j <= n, is a pointer to the list of elements in
+         j-th column of matrix V (except pivot elements) */
+      int *P_row; /* int P_row[1+n]; */
+      /* P_row[0] is not used;
+         P_row[i] = j means that p[i,j] = 1, where p[i,j] is an element
+         of permutation matrix P */
+      int *P_col; /* int P_col[1+n]; */
+      /* P_col[0] is not used;
+         P_col[j] = i means that p[i,j] = 1, where p[i,j] is an element
+         of permutation matrix P */
+      /* if i-th row or column of matrix F is i'-th row or column of
+         matrix L = P*F*inv(P), or if i-th row of matrix V is i'-th row
+         of matrix U = P*V*Q, then P_row[i'] = i and P_col[i] = i' */
+      int *Q_row; /* int Q_row[1+n]; */
+      /* Q_row[0] is not used;
+         Q_row[i] = j means that q[i,j] = 1, where q[i,j] is an element
+         of permutation matrix Q */
+      int *Q_col; /* int Q_col[1+n]; */
+      /* Q_col[0] is not used;
+         Q_col[j] = i means that q[i,j] = 1, where q[i,j] is an element
+         of permutation matrix Q */
+      /* if j-th column of matrix V is j'-th column of matrix U = P*V*Q,
+         then Q_row[j] = j' and Q_col[j'] = j */
+      int rank;
+      /* the (exact) rank of matrices A and V */
+};
+
+struct LUXELM
+{     /* element of matrix F or V */
+      int i;
+      /* row index, 1 <= i <= m */
+      int j;
+      /* column index, 1 <= j <= n */
+      mpq_t val;
+      /* numeric (non-zero) element value */
+      LUXELM *r_prev;
+      /* pointer to previous element in the same row */
+      LUXELM *r_next;
+      /* pointer to next element in the same row */
+      LUXELM *c_prev;
+      /* pointer to previous element in the same column */
+      LUXELM *c_next;
+      /* pointer to next element in the same column */
+};
+
+struct LUXWKA
+{     /* working area (used only during factorization) */
+      /* in order to efficiently implement Markowitz strategy and Duff
+         search technique there are two families {R[0], R[1], ..., R[n]}
+         and {C[0], C[1], ..., C[n]}; member R[k] is a set of active
+         rows of matrix V having k non-zeros, and member C[k] is a set
+         of active columns of matrix V having k non-zeros (in the active
+         submatrix); each set R[k] and C[k] is implemented as a separate
+         doubly linked list */
+      int *R_len; /* int R_len[1+n]; */
+      /* R_len[0] is not used;
+         R_len[i], 1 <= i <= n, is the number of non-zero elements in
+         i-th row of matrix V (that is the length of i-th row) */
+      int *R_head; /* int R_head[1+n]; */
+      /* R_head[k], 0 <= k <= n, is the number of a first row, which is
+         active and whose length is k */
+      int *R_prev; /* int R_prev[1+n]; */
+      /* R_prev[0] is not used;
+         R_prev[i], 1 <= i <= n, is the number of a previous row, which
+         is active and has the same length as i-th row */
+      int *R_next; /* int R_next[1+n]; */
+      /* R_prev[0] is not used;
+         R_prev[i], 1 <= i <= n, is the number of a next row, which is
+         active and has the same length as i-th row */
+      int *C_len; /* int C_len[1+n]; */
+      /* C_len[0] is not used;
+         C_len[j], 1 <= j <= n, is the number of non-zero elements in
+         j-th column of the active submatrix of matrix V (that is the
+         length of j-th column in the active submatrix) */
+      int *C_head; /* int C_head[1+n]; */
+      /* C_head[k], 0 <= k <= n, is the number of a first column, which
+         is active and whose length is k */
+      int *C_prev; /* int C_prev[1+n]; */
+      /* C_prev[0] is not used;
+         C_prev[j], 1 <= j <= n, is the number of a previous column,
+         which is active and has the same length as j-th column */
+      int *C_next; /* int C_next[1+n]; */
+      /* C_next[0] is not used;
+         C_next[j], 1 <= j <= n, is the number of a next column, which
+         is active and has the same length as j-th column */
+};
+
+#define lux_create            _glp_lux_create
+#define lux_decomp            _glp_lux_decomp
+#define lux_f_solve           _glp_lux_f_solve
+#define lux_v_solve           _glp_lux_v_solve
+#define lux_solve             _glp_lux_solve
+#define lux_delete            _glp_lux_delete
+
+LUX *lux_create(int n);
+/* create LU-factorization */
+
+int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
+      mpq_t val[]), void *info);
+/* compute LU-factorization */
+
+void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system F*x = b or F'*x = b */
+
+void lux_v_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system V*x = b or V'*x = b */
+
+void lux_solve(LUX *lux, int tr, mpq_t x[]);
+/* solve system A*x = b or A'*x = b */
+
+void lux_delete(LUX *lux);
+/* delete LU-factorization */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpmat.c
===================================================================
--- deps/glpk/src/glpmat.c	(revision 9)
+++ deps/glpk/src/glpmat.c	(revision 9)
@@ -0,0 +1,924 @@
+/* glpmat.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpmat.h"
+#include "glpqmd.h"
+#include "amd/amd.h"
+#include "colamd/colamd.h"
+
+/*----------------------------------------------------------------------
+-- check_fvs - check sparse vector in full-vector storage format.
+--
+-- SYNOPSIS
+--
+-- #include "glpmat.h"
+-- int check_fvs(int n, int nnz, int ind[], double vec[]);
+--
+-- DESCRIPTION
+--
+-- The routine check_fvs checks if a given vector of dimension n in
+-- full-vector storage format has correct representation.
+--
+-- RETURNS
+--
+-- The routine returns one of the following codes:
+--
+-- 0 - the vector is correct;
+-- 1 - the number of elements (n) is negative;
+-- 2 - the number of non-zero elements (nnz) is negative;
+-- 3 - some element index is out of range;
+-- 4 - some element index is duplicate;
+-- 5 - some non-zero element is out of pattern. */
+
+int check_fvs(int n, int nnz, int ind[], double vec[])
+{     int i, t, ret, *flag = NULL;
+      /* check the number of elements */
+      if (n < 0)
+      {  ret = 1;
+         goto done;
+      }
+      /* check the number of non-zero elements */
+      if (nnz < 0)
+      {  ret = 2;
+         goto done;
+      }
+      /* check vector indices */
+      flag = xcalloc(1+n, sizeof(int));
+      for (i = 1; i <= n; i++) flag[i] = 0;
+      for (t = 1; t <= nnz; t++)
+      {  i = ind[t];
+         if (!(1 <= i && i <= n))
+         {  ret = 3;
+            goto done;
+         }
+         if (flag[i])
+         {  ret = 4;
+            goto done;
+         }
+         flag[i] = 1;
+      }
+      /* check vector elements */
+      for (i = 1; i <= n; i++)
+      {  if (!flag[i] && vec[i] != 0.0)
+         {  ret = 5;
+            goto done;
+         }
+      }
+      /* the vector is ok */
+      ret = 0;
+done: if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+-- check_pattern - check pattern of sparse matrix.
+--
+-- SYNOPSIS
+--
+-- #include "glpmat.h"
+-- int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
+--
+-- DESCRIPTION
+--
+-- The routine check_pattern checks the pattern of a given mxn matrix
+-- in storage-by-rows format.
+--
+-- RETURNS
+--
+-- The routine returns one of the following codes:
+--
+-- 0 - the pattern is correct;
+-- 1 - the number of rows (m) is negative;
+-- 2 - the number of columns (n) is negative;
+-- 3 - A_ptr[1] is not 1;
+-- 4 - some column index is out of range;
+-- 5 - some column indices are duplicate. */
+
+int check_pattern(int m, int n, int A_ptr[], int A_ind[])
+{     int i, j, ptr, ret, *flag = NULL;
+      /* check the number of rows */
+      if (m < 0)
+      {  ret = 1;
+         goto done;
+      }
+      /* check the number of columns */
+      if (n < 0)
+      {  ret = 2;
+         goto done;
+      }
+      /* check location A_ptr[1] */
+      if (A_ptr[1] != 1)
+      {  ret = 3;
+         goto done;
+      }
+      /* check row patterns */
+      flag = xcalloc(1+n, sizeof(int));
+      for (j = 1; j <= n; j++) flag[j] = 0;
+      for (i = 1; i <= m; i++)
+      {  /* check pattern of row i */
+         for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
+         {  j = A_ind[ptr];
+            /* check column index */
+            if (!(1 <= j && j <= n))
+            {  ret = 4;
+               goto done;
+            }
+            /* check for duplication */
+            if (flag[j])
+            {  ret = 5;
+               goto done;
+            }
+            flag[j] = 1;
+         }
+         /* clear flags */
+         for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++)
+         {  j = A_ind[ptr];
+            flag[j] = 0;
+         }
+      }
+      /* the pattern is ok */
+      ret = 0;
+done: if (flag != NULL) xfree(flag);
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+-- transpose - transpose sparse matrix.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void transpose(int m, int n, int A_ptr[], int A_ind[],
+--    double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]);
+--
+-- *Description*
+--
+-- For a given mxn sparse matrix A the routine transpose builds a nxm
+-- sparse matrix A' which is a matrix transposed to A.
+--
+-- The arrays A_ptr, A_ind, and A_val specify a given mxn matrix A to
+-- be transposed in storage-by-rows format. The parameter A_val can be
+-- NULL, in which case numeric values are not copied. The arrays A_ptr,
+-- A_ind, and A_val are not changed on exit.
+--
+-- On entry the arrays AT_ptr, AT_ind, and AT_val must be allocated,
+-- but their content is ignored. On exit the routine stores a resultant
+-- nxm matrix A' in these arrays in storage-by-rows format. Note that
+-- if the parameter A_val is NULL, the array AT_val is not used.
+--
+-- The routine transpose has a side effect that elements in rows of the
+-- resultant matrix A' follow in ascending their column indices. */
+
+void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
+      int AT_ptr[], int AT_ind[], double AT_val[])
+{     int i, j, t, beg, end, pos, len;
+      /* determine row lengths of resultant matrix */
+      for (j = 1; j <= n; j++) AT_ptr[j] = 0;
+      for (i = 1; i <= m; i++)
+      {  beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++) AT_ptr[A_ind[t]]++;
+      }
+      /* set up row pointers of resultant matrix */
+      pos = 1;
+      for (j = 1; j <= n; j++)
+         len = AT_ptr[j], pos += len, AT_ptr[j] = pos;
+      AT_ptr[n+1] = pos;
+      /* build resultant matrix */
+      for (i = m; i >= 1; i--)
+      {  beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+         {  pos = --AT_ptr[A_ind[t]];
+            AT_ind[pos] = i;
+            if (A_val != NULL) AT_val[pos] = A_val[t];
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- adat_symbolic - compute S = P*A*D*A'*P' (symbolic phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int *adat_symbolic(int m, int n, int P_per[], int A_ptr[],
+--    int A_ind[], int S_ptr[]);
+--
+-- *Description*
+--
+-- The routine adat_symbolic implements the symbolic phase to compute
+-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
+-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
+-- transposed to A, P' is an inverse of P.
+--
+-- The parameter m is the number of rows in A and the order of P.
+--
+-- The parameter n is the number of columns in A and the order of D.
+--
+-- The array P_per specifies permutation matrix P. It is not changed on
+-- exit.
+--
+-- The arrays A_ptr and A_ind specify the pattern of matrix A. They are
+-- not changed on exit.
+--
+-- On exit the routine stores the pattern of upper triangular part of
+-- matrix S without diagonal elements in the arrays S_ptr and S_ind in
+-- storage-by-rows format. The array S_ptr should be allocated on entry,
+-- however, its content is ignored. The array S_ind is allocated by the
+-- routine itself which returns a pointer to it.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the array S_ind. */
+
+int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
+      int S_ptr[])
+{     int i, j, t, ii, jj, tt, k, size, len;
+      int *S_ind, *AT_ptr, *AT_ind, *ind, *map, *temp;
+      /* build the pattern of A', which is a matrix transposed to A, to
+         efficiently access A in column-wise manner */
+      AT_ptr = xcalloc(1+n+1, sizeof(int));
+      AT_ind = xcalloc(A_ptr[m+1], sizeof(int));
+      transpose(m, n, A_ptr, A_ind, NULL, AT_ptr, AT_ind, NULL);
+      /* allocate the array S_ind */
+      size = A_ptr[m+1] - 1;
+      if (size < m) size = m;
+      S_ind = xcalloc(1+size, sizeof(int));
+      /* allocate and initialize working arrays */
+      ind = xcalloc(1+m, sizeof(int));
+      map = xcalloc(1+m, sizeof(int));
+      for (jj = 1; jj <= m; jj++) map[jj] = 0;
+      /* compute pattern of S; note that symbolically S = B*B', where
+         B = P*A, B' is matrix transposed to B */
+      S_ptr[1] = 1;
+      for (ii = 1; ii <= m; ii++)
+      {  /* compute pattern of ii-th row of S */
+         len = 0;
+         i = P_per[ii]; /* i-th row of A = ii-th row of B */
+         for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+         {  k = A_ind[t];
+            /* walk through k-th column of A */
+            for (tt = AT_ptr[k]; tt < AT_ptr[k+1]; tt++)
+            {  j = AT_ind[tt];
+               jj = P_per[m+j]; /* j-th row of A = jj-th row of B */
+               /* a[i,k] != 0 and a[j,k] != 0 ergo s[ii,jj] != 0 */
+               if (ii < jj && !map[jj]) ind[++len] = jj, map[jj] = 1;
+            }
+         }
+         /* now (ind) is pattern of ii-th row of S */
+         S_ptr[ii+1] = S_ptr[ii] + len;
+         /* at least (S_ptr[ii+1] - 1) locations should be available in
+            the array S_ind */
+         if (S_ptr[ii+1] - 1 > size)
+         {  temp = S_ind;
+            size += size;
+            S_ind = xcalloc(1+size, sizeof(int));
+            memcpy(&S_ind[1], &temp[1], (S_ptr[ii] - 1) * sizeof(int));
+            xfree(temp);
+         }
+         xassert(S_ptr[ii+1] - 1 <= size);
+         /* (ii-th row of S) := (ind) */
+         memcpy(&S_ind[S_ptr[ii]], &ind[1], len * sizeof(int));
+         /* clear the row pattern map */
+         for (t = 1; t <= len; t++) map[ind[t]] = 0;
+      }
+      /* free working arrays */
+      xfree(AT_ptr);
+      xfree(AT_ind);
+      xfree(ind);
+      xfree(map);
+      /* reallocate the array S_ind to free unused locations */
+      temp = S_ind;
+      size = S_ptr[m+1] - 1;
+      S_ind = xcalloc(1+size, sizeof(int));
+      memcpy(&S_ind[1], &temp[1], size * sizeof(int));
+      xfree(temp);
+      return S_ind;
+}
+
+/*----------------------------------------------------------------------
+-- adat_numeric - compute S = P*A*D*A'*P' (numeric phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void adat_numeric(int m, int n, int P_per[],
+--    int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+--    int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
+--
+-- *Description*
+--
+-- The routine adat_numeric implements the numeric phase to compute
+-- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix,
+-- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix
+-- transposed to A, P' is an inverse of P.
+--
+-- The parameter m is the number of rows in A and the order of P.
+--
+-- The parameter n is the number of columns in A and the order of D.
+--
+-- The matrix P is specified in the array P_per, which is not changed
+-- on exit.
+--
+-- The matrix A is specified in the arrays A_ptr, A_ind, and A_val in
+-- storage-by-rows format. These arrays are not changed on exit.
+--
+-- Diagonal elements of the matrix D are specified in the array D_diag,
+-- where D_diag[0] is not used, D_diag[i] = d[i,i] for i = 1, ..., n.
+-- The array D_diag is not changed on exit.
+--
+-- The pattern of the upper triangular part of the matrix S without
+-- diagonal elements (previously computed by the routine adat_symbolic)
+-- is specified in the arrays S_ptr and S_ind, which are not changed on
+-- exit. Numeric values of non-diagonal elements of S are stored in
+-- corresponding locations of the array S_val, and values of diagonal
+-- elements of S are stored in locations S_diag[1], ..., S_diag[n]. */
+
+void adat_numeric(int m, int n, int P_per[],
+      int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+      int S_ptr[], int S_ind[], double S_val[], double S_diag[])
+{     int i, j, t, ii, jj, tt, beg, end, beg1, end1, k;
+      double sum, *work;
+      work = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++) work[j] = 0.0;
+      /* compute S = B*D*B', where B = P*A, B' is a matrix transposed
+         to B */
+      for (ii = 1; ii <= m; ii++)
+      {  i = P_per[ii]; /* i-th row of A = ii-th row of B */
+         /* (work) := (i-th row of A) */
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+            work[A_ind[t]] = A_val[t];
+         /* compute ii-th row of S */
+         beg = S_ptr[ii], end = S_ptr[ii+1];
+         for (t = beg; t < end; t++)
+         {  jj = S_ind[t];
+            j = P_per[jj]; /* j-th row of A = jj-th row of B */
+            /* s[ii,jj] := sum a[i,k] * d[k,k] * a[j,k] */
+            sum = 0.0;
+            beg1 = A_ptr[j], end1 = A_ptr[j+1];
+            for (tt = beg1; tt < end1; tt++)
+            {  k = A_ind[tt];
+               sum += work[k] * D_diag[k] * A_val[tt];
+            }
+            S_val[t] = sum;
+         }
+         /* s[ii,ii] := sum a[i,k] * d[k,k] * a[i,k] */
+         sum = 0.0;
+         beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+         {  k = A_ind[t];
+            sum += A_val[t] * D_diag[k] * A_val[t];
+            work[k] = 0.0;
+         }
+         S_diag[ii] = sum;
+      }
+      xfree(work);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- min_degree - minimum degree ordering.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
+--
+-- *Description*
+--
+-- The routine min_degree uses the minimum degree ordering algorithm
+-- to find a permutation matrix P for a given sparse symmetric positive
+-- matrix A which minimizes the number of non-zeros in upper triangular
+-- factor U for Cholesky factorization P*A*P' = U'*U.
+--
+-- The parameter n is the order of matrices A and P.
+--
+-- The pattern of the given matrix A is specified on entry in the arrays
+-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
+-- part without diagonal elements (which all are assumed to be non-zero)
+-- should be specified as if A were upper triangular. The arrays A_ptr
+-- and A_ind are not changed on exit.
+--
+-- The permutation matrix P is stored by the routine in the array P_per
+-- on exit.
+--
+-- *Algorithm*
+--
+-- The routine min_degree is based on some subroutines from the package
+-- SPARSPAK (see comments in the module glpqmd). */
+
+void min_degree(int n, int A_ptr[], int A_ind[], int P_per[])
+{     int i, j, ne, t, pos, len;
+      int *xadj, *adjncy, *deg, *marker, *rchset, *nbrhd, *qsize,
+         *qlink, nofsub;
+      /* determine number of non-zeros in complete pattern */
+      ne = A_ptr[n+1] - 1;
+      ne += ne;
+      /* allocate working arrays */
+      xadj = xcalloc(1+n+1, sizeof(int));
+      adjncy = xcalloc(1+ne, sizeof(int));
+      deg = xcalloc(1+n, sizeof(int));
+      marker = xcalloc(1+n, sizeof(int));
+      rchset = xcalloc(1+n, sizeof(int));
+      nbrhd = xcalloc(1+n, sizeof(int));
+      qsize = xcalloc(1+n, sizeof(int));
+      qlink = xcalloc(1+n, sizeof(int));
+      /* determine row lengths in complete pattern */
+      for (i = 1; i <= n; i++) xadj[i] = 0;
+      for (i = 1; i <= n; i++)
+      {  for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+         {  j = A_ind[t];
+            xassert(i < j && j <= n);
+            xadj[i]++, xadj[j]++;
+         }
+      }
+      /* set up row pointers for complete pattern */
+      pos = 1;
+      for (i = 1; i <= n; i++)
+         len = xadj[i], pos += len, xadj[i] = pos;
+      xadj[n+1] = pos;
+      xassert(pos - 1 == ne);
+      /* construct complete pattern */
+      for (i = 1; i <= n; i++)
+      {  for (t = A_ptr[i]; t < A_ptr[i+1]; t++)
+         {  j = A_ind[t];
+            adjncy[--xadj[i]] = j, adjncy[--xadj[j]] = i;
+         }
+      }
+      /* call the main minimimum degree ordering routine */
+      genqmd(&n, xadj, adjncy, P_per, P_per + n, deg, marker, rchset,
+         nbrhd, qsize, qlink, &nofsub);
+      /* make sure that permutation matrix P is correct */
+      for (i = 1; i <= n; i++)
+      {  j = P_per[i];
+         xassert(1 <= j && j <= n);
+         xassert(P_per[n+j] == i);
+      }
+      /* free working arrays */
+      xfree(xadj);
+      xfree(adjncy);
+      xfree(deg);
+      xfree(marker);
+      xfree(rchset);
+      xfree(nbrhd);
+      xfree(qsize);
+      xfree(qlink);
+      return;
+}
+
+/**********************************************************************/
+
+void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[])
+{     /* approximate minimum degree ordering (AMD) */
+      int k, ret;
+      double Control[AMD_CONTROL], Info[AMD_INFO];
+      /* get the default parameters */
+      amd_defaults(Control);
+#if 0
+      /* and print them */
+      amd_control(Control);
+#endif
+      /* make all indices 0-based */
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
+      for (k = 1; k <= n+1; k++) A_ptr[k]--;
+      /* call the ordering routine */
+      ret = amd_order(n, &A_ptr[1], &A_ind[1], &P_per[1], Control, Info)
+         ;
+#if 0
+      amd_info(Info);
+#endif
+      xassert(ret == AMD_OK || ret == AMD_OK_BUT_JUMBLED);
+      /* retsore 1-based indices */
+      for (k = 1; k <= n+1; k++) A_ptr[k]++;
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
+      /* patch up permutation matrix */
+      memset(&P_per[n+1], 0, n * sizeof(int));
+      for (k = 1; k <= n; k++)
+      {  P_per[k]++;
+         xassert(1 <= P_per[k] && P_per[k] <= n);
+         xassert(P_per[n+P_per[k]] == 0);
+         P_per[n+P_per[k]] = k;
+      }
+      return;
+}
+
+/**********************************************************************/
+
+static void *allocate(size_t n, size_t size)
+{     void *ptr;
+      ptr = xcalloc(n, size);
+      memset(ptr, 0, n * size);
+      return ptr;
+}
+
+static void release(void *ptr)
+{     xfree(ptr);
+      return;
+}
+
+void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[])
+{     /* approximate minimum degree ordering (SYMAMD) */
+      int k, ok;
+      int stats[COLAMD_STATS];
+      /* make all indices 0-based */
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--;
+      for (k = 1; k <= n+1; k++) A_ptr[k]--;
+      /* call the ordering routine */
+      ok = symamd(n, &A_ind[1], &A_ptr[1], &P_per[1], NULL, stats,
+         allocate, release);
+#if 0
+      symamd_report(stats);
+#endif
+      xassert(ok);
+      /* restore 1-based indices */
+      for (k = 1; k <= n+1; k++) A_ptr[k]++;
+      for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++;
+      /* patch up permutation matrix */
+      memset(&P_per[n+1], 0, n * sizeof(int));
+      for (k = 1; k <= n; k++)
+      {  P_per[k]++;
+         xassert(1 <= P_per[k] && P_per[k] <= n);
+         xassert(P_per[n+P_per[k]] == 0);
+         P_per[n+P_per[k]] = k;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- chol_symbolic - compute Cholesky factorization (symbolic phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
+--
+-- *Description*
+--
+-- The routine chol_symbolic implements the symbolic phase of Cholesky
+-- factorization A = U'*U, where A is a given sparse symmetric positive
+-- definite matrix, U is a resultant upper triangular factor, U' is a
+-- matrix transposed to U.
+--
+-- The parameter n is the order of matrices A and U.
+--
+-- The pattern of the given matrix A is specified on entry in the arrays
+-- A_ptr and A_ind in storage-by-rows format. Only the upper triangular
+-- part without diagonal elements (which all are assumed to be non-zero)
+-- should be specified as if A were upper triangular. The arrays A_ptr
+-- and A_ind are not changed on exit.
+--
+-- The pattern of the matrix U without diagonal elements (which all are
+-- assumed to be non-zero) is stored on exit from the routine in the
+-- arrays U_ptr and U_ind in storage-by-rows format. The array U_ptr
+-- should be allocated on entry, however, its content is ignored. The
+-- array U_ind is allocated by the routine which returns a pointer to it
+-- on exit.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the array U_ind.
+--
+-- *Method*
+--
+-- The routine chol_symbolic computes the pattern of the matrix U in a
+-- row-wise manner. No pivoting is used.
+--
+-- It is known that to compute the pattern of row k of the matrix U we
+-- need to merge the pattern of row k of the matrix A and the patterns
+-- of each row i of U, where u[i,k] is non-zero (these rows are already
+-- computed and placed above row k).
+--
+-- However, to reduce the number of rows to be merged the routine uses
+-- an advanced algorithm proposed in:
+--
+-- D.J.Rose, R.E.Tarjan, and G.S.Lueker. Algorithmic aspects of vertex
+-- elimination on graphs. SIAM J. Comput. 5, 1976, 266-83.
+--
+-- The authors of the cited paper show that we have the same result if
+-- we merge row k of the matrix A and such rows of the matrix U (among
+-- rows 1, ..., k-1) whose leftmost non-diagonal non-zero element is
+-- placed in k-th column. This feature signficantly reduces the number
+-- of rows to be merged, especially on the final steps, where rows of
+-- the matrix U become quite dense.
+--
+-- To determine rows, which should be merged on k-th step, for a fixed
+-- time the routine uses linked lists of row numbers of the matrix U.
+-- Location head[k] contains the number of a first row, whose leftmost
+-- non-diagonal non-zero element is placed in column k, and location
+-- next[i] contains the number of a next row with the same property as
+-- row i. */
+
+int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[])
+{     int i, j, k, t, len, size, beg, end, min_j, *U_ind, *head, *next,
+         *ind, *map, *temp;
+      /* initially we assume that on computing the pattern of U fill-in
+         will double the number of non-zeros in A */
+      size = A_ptr[n+1] - 1;
+      if (size < n) size = n;
+      size += size;
+      U_ind = xcalloc(1+size, sizeof(int));
+      /* allocate and initialize working arrays */
+      head = xcalloc(1+n, sizeof(int));
+      for (i = 1; i <= n; i++) head[i] = 0;
+      next = xcalloc(1+n, sizeof(int));
+      ind = xcalloc(1+n, sizeof(int));
+      map = xcalloc(1+n, sizeof(int));
+      for (j = 1; j <= n; j++) map[j] = 0;
+      /* compute the pattern of matrix U */
+      U_ptr[1] = 1;
+      for (k = 1; k <= n; k++)
+      {  /* compute the pattern of k-th row of U, which is the union of
+            k-th row of A and those rows of U (among 1, ..., k-1) whose
+            leftmost non-diagonal non-zero is placed in k-th column */
+         /* (ind) := (k-th row of A) */
+         len = A_ptr[k+1] - A_ptr[k];
+         memcpy(&ind[1], &A_ind[A_ptr[k]], len * sizeof(int));
+         for (t = 1; t <= len; t++)
+         {  j = ind[t];
+            xassert(k < j && j <= n);
+            map[j] = 1;
+         }
+         /* walk through rows of U whose leftmost non-diagonal non-zero
+            is placed in k-th column */
+         for (i = head[k]; i != 0; i = next[i])
+         {  /* (ind) := (ind) union (i-th row of U) */
+            beg = U_ptr[i], end = U_ptr[i+1];
+            for (t = beg; t < end; t++)
+            {  j = U_ind[t];
+               if (j > k && !map[j]) ind[++len] = j, map[j] = 1;
+            }
+         }
+         /* now (ind) is the pattern of k-th row of U */
+         U_ptr[k+1] = U_ptr[k] + len;
+         /* at least (U_ptr[k+1] - 1) locations should be available in
+            the array U_ind */
+         if (U_ptr[k+1] - 1 > size)
+         {  temp = U_ind;
+            size += size;
+            U_ind = xcalloc(1+size, sizeof(int));
+            memcpy(&U_ind[1], &temp[1], (U_ptr[k] - 1) * sizeof(int));
+            xfree(temp);
+         }
+         xassert(U_ptr[k+1] - 1 <= size);
+         /* (k-th row of U) := (ind) */
+         memcpy(&U_ind[U_ptr[k]], &ind[1], len * sizeof(int));
+         /* determine column index of leftmost non-diagonal non-zero in
+            k-th row of U and clear the row pattern map */
+         min_j = n + 1;
+         for (t = 1; t <= len; t++)
+         {  j = ind[t], map[j] = 0;
+            if (min_j > j) min_j = j;
+         }
+         /* include k-th row into corresponding linked list */
+         if (min_j <= n) next[k] = head[min_j], head[min_j] = k;
+      }
+      /* free working arrays */
+      xfree(head);
+      xfree(next);
+      xfree(ind);
+      xfree(map);
+      /* reallocate the array U_ind to free unused locations */
+      temp = U_ind;
+      size = U_ptr[n+1] - 1;
+      U_ind = xcalloc(1+size, sizeof(int));
+      memcpy(&U_ind[1], &temp[1], size * sizeof(int));
+      xfree(temp);
+      return U_ind;
+}
+
+/*----------------------------------------------------------------------
+-- chol_numeric - compute Cholesky factorization (numeric phase).
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- int chol_numeric(int n,
+--    int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+--    int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
+--
+-- *Description*
+--
+-- The routine chol_symbolic implements the numeric phase of Cholesky
+-- factorization A = U'*U, where A is a given sparse symmetric positive
+-- definite matrix, U is a resultant upper triangular factor, U' is a
+-- matrix transposed to U.
+--
+-- The parameter n is the order of matrices A and U.
+--
+-- Upper triangular part of the matrix A without diagonal elements is
+-- specified in the arrays A_ptr, A_ind, and A_val in storage-by-rows
+-- format. Diagonal elements of A are specified in the array A_diag,
+-- where A_diag[0] is not used, A_diag[i] = a[i,i] for i = 1, ..., n.
+-- The arrays A_ptr, A_ind, A_val, and A_diag are not changed on exit.
+--
+-- The pattern of the matrix U without diagonal elements (previously
+-- computed with the routine chol_symbolic) is specified in the arrays
+-- U_ptr and U_ind, which are not changed on exit. Numeric values of
+-- non-diagonal elements of U are stored in corresponding locations of
+-- the array U_val, and values of diagonal elements of U are stored in
+-- locations U_diag[1], ..., U_diag[n].
+--
+-- *Returns*
+--
+-- The routine returns the number of non-positive diagonal elements of
+-- the matrix U which have been replaced by a huge positive number (see
+-- the method description below). Zero return code means the matrix A
+-- has been successfully factorized.
+--
+-- *Method*
+--
+-- The routine chol_numeric computes the matrix U in a row-wise manner
+-- using standard gaussian elimination technique. No pivoting is used.
+--
+-- Initially the routine sets U = A, and before k-th elimination step
+-- the matrix U is the following:
+--
+--       1       k         n
+--    1  x x x x x x x x x x
+--       . x x x x x x x x x
+--       . . x x x x x x x x
+--       . . . x x x x x x x
+--    k  . . . . * * * * * *
+--       . . . . * * * * * *
+--       . . . . * * * * * *
+--       . . . . * * * * * *
+--       . . . . * * * * * *
+--    n  . . . . * * * * * *
+--
+-- where 'x' are elements of already computed rows, '*' are elements of
+-- the active submatrix. (Note that the lower triangular part of the
+-- active submatrix being symmetric is not stored and diagonal elements
+-- are stored separately in the array U_diag.)
+--
+-- The matrix A is assumed to be positive definite. However, if it is
+-- close to semi-definite, on some elimination step a pivot u[k,k] may
+-- happen to be non-positive due to round-off errors. In this case the
+-- routine uses a technique proposed in:
+--
+-- S.J.Wright. The Cholesky factorization in interior-point and barrier
+-- methods. Preprint MCS-P600-0596, Mathematics and Computer Science
+-- Division, Argonne National Laboratory, Argonne, Ill., May 1996.
+--
+-- The routine just replaces non-positive u[k,k] by a huge positive
+-- number. This involves non-diagonal elements in k-th row of U to be
+-- close to zero that, in turn, involves k-th component of a solution
+-- vector to be close to zero. Note, however, that this technique works
+-- only if the system A*x = b is consistent. */
+
+int chol_numeric(int n,
+      int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+      int U_ptr[], int U_ind[], double U_val[], double U_diag[])
+{     int i, j, k, t, t1, beg, end, beg1, end1, count = 0;
+      double ukk, uki, *work;
+      work = xcalloc(1+n, sizeof(double));
+      for (j = 1; j <= n; j++) work[j] = 0.0;
+      /* U := (upper triangle of A) */
+      /* note that the upper traingle of A is a subset of U */
+      for (i = 1; i <= n; i++)
+      {  beg = A_ptr[i], end = A_ptr[i+1];
+         for (t = beg; t < end; t++)
+            j = A_ind[t], work[j] = A_val[t];
+         beg = U_ptr[i], end = U_ptr[i+1];
+         for (t = beg; t < end; t++)
+            j = U_ind[t], U_val[t] = work[j], work[j] = 0.0;
+         U_diag[i] = A_diag[i];
+      }
+      /* main elimination loop */
+      for (k = 1; k <= n; k++)
+      {  /* transform k-th row of U */
+         ukk = U_diag[k];
+         if (ukk > 0.0)
+            U_diag[k] = ukk = sqrt(ukk);
+         else
+            U_diag[k] = ukk = DBL_MAX, count++;
+         /* (work) := (transformed k-th row) */
+         beg = U_ptr[k], end = U_ptr[k+1];
+         for (t = beg; t < end; t++)
+            work[U_ind[t]] = (U_val[t] /= ukk);
+         /* transform other rows of U */
+         for (t = beg; t < end; t++)
+         {  i = U_ind[t];
+            xassert(i > k);
+            /* (i-th row) := (i-th row) - u[k,i] * (k-th row) */
+            uki = work[i];
+            beg1 = U_ptr[i], end1 = U_ptr[i+1];
+            for (t1 = beg1; t1 < end1; t1++)
+               U_val[t1] -= uki * work[U_ind[t1]];
+            U_diag[i] -= uki * uki;
+         }
+         /* (work) := 0 */
+         for (t = beg; t < end; t++)
+            work[U_ind[t]] = 0.0;
+      }
+      xfree(work);
+      return count;
+}
+
+/*----------------------------------------------------------------------
+-- u_solve - solve upper triangular system U*x = b.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+--    double U_diag[], double x[]);
+--
+-- *Description*
+--
+-- The routine u_solve solves an linear system U*x = b, where U is an
+-- upper triangular matrix.
+--
+-- The parameter n is the order of matrix U.
+--
+-- The matrix U without diagonal elements is specified in the arrays
+-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
+-- of U are specified in the array U_diag, where U_diag[0] is not used,
+-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
+-- changed on exit.
+--
+-- The right-hand side vector b is specified on entry in the array x,
+-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
+-- the routine stores computed components of the vector of unknowns x
+-- in the array x in the same manner. */
+
+void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[])
+{     int i, t, beg, end;
+      double temp;
+      for (i = n; i >= 1; i--)
+      {  temp = x[i];
+         beg = U_ptr[i], end = U_ptr[i+1];
+         for (t = beg; t < end; t++)
+            temp -= U_val[t] * x[U_ind[t]];
+         xassert(U_diag[i] != 0.0);
+         x[i] = temp / U_diag[i];
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- ut_solve - solve lower triangular system U'*x = b.
+--
+-- *Synopsis*
+--
+-- #include "glpmat.h"
+-- void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+--    double U_diag[], double x[]);
+--
+-- *Description*
+--
+-- The routine ut_solve solves an linear system U'*x = b, where U is a
+-- matrix transposed to an upper triangular matrix.
+--
+-- The parameter n is the order of matrix U.
+--
+-- The matrix U without diagonal elements is specified in the arrays
+-- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements
+-- of U are specified in the array U_diag, where U_diag[0] is not used,
+-- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not
+-- changed on exit.
+--
+-- The right-hand side vector b is specified on entry in the array x,
+-- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit
+-- the routine stores computed components of the vector of unknowns x
+-- in the array x in the same manner. */
+
+void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[])
+{     int i, t, beg, end;
+      double temp;
+      for (i = 1; i <= n; i++)
+      {  xassert(U_diag[i] != 0.0);
+         temp = (x[i] /= U_diag[i]);
+         if (temp == 0.0) continue;
+         beg = U_ptr[i], end = U_ptr[i+1];
+         for (t = beg; t < end; t++)
+            x[U_ind[t]] -= U_val[t] * temp;
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpmat.h
===================================================================
--- deps/glpk/src/glpmat.h	(revision 9)
+++ deps/glpk/src/glpmat.h	(revision 9)
@@ -0,0 +1,198 @@
+/* glpmat.h (linear algebra routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPMAT_H
+#define GLPMAT_H
+
+/***********************************************************************
+*  FULL-VECTOR STORAGE
+* 
+*  For a sparse vector x having n elements, ne of which are non-zero,
+*  the full-vector storage format uses two arrays x_ind and x_vec, which
+*  are set up as follows:
+* 
+*  x_ind is an integer array of length [1+ne]. Location x_ind[0] is
+*  not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
+*  non-zero elements in vector x.
+* 
+*  x_vec is a floating-point array of length [1+n]. Location x_vec[0]
+*  is not used, and locations x_vec[1], ..., x_vec[n] contain numeric
+*  values of ALL elements in vector x, including its zero elements.
+* 
+*  Let, for example, the following sparse vector x be given:
+* 
+*     (0, 1, 0, 0, 2, 3, 0, 4)
+* 
+*  Then the arrays are:
+* 
+*     x_ind = { X; 2, 5, 6, 8 }
+* 
+*     x_vec = { X; 0, 1, 0, 0, 2, 3, 0, 4 }
+* 
+*  COMPRESSED-VECTOR STORAGE
+* 
+*  For a sparse vector x having n elements, ne of which are non-zero,
+*  the compressed-vector storage format uses two arrays x_ind and x_vec,
+*  which are set up as follows:
+* 
+*  x_ind is an integer array of length [1+ne]. Location x_ind[0] is
+*  not used, and locations x_ind[1], ..., x_ind[ne] contain indices of
+*  non-zero elements in vector x.
+* 
+*  x_vec is a floating-point array of length [1+ne]. Location x_vec[0]
+*  is not used, and locations x_vec[1], ..., x_vec[ne] contain numeric
+*  values of corresponding non-zero elements in vector x.
+* 
+*  Let, for example, the following sparse vector x be given:
+* 
+*     (0, 1, 0, 0, 2, 3, 0, 4)
+* 
+*  Then the arrays are:
+*
+*     x_ind = { X; 2, 5, 6, 8 }
+* 
+*     x_vec = { X; 1, 2, 3, 4 }
+* 
+*  STORAGE-BY-ROWS
+* 
+*  For a sparse matrix A, which has m rows, n columns, and ne non-zero
+*  elements the storage-by-rows format uses three arrays A_ptr, A_ind,
+*  and A_val, which are set up as follows:
+* 
+*  A_ptr is an integer array of length [1+m+1] also called "row pointer
+*  array". It contains the relative starting positions of each row of A
+*  in the arrays A_ind and A_val, i.e. element A_ptr[i], 1 <= i <= m,
+*  indicates where row i begins in the arrays A_ind and A_val. If all
+*  elements in row i are zero, then A_ptr[i] = A_ptr[i+1]. Location
+*  A_ptr[0] is not used, location A_ptr[1] must contain 1, and location
+*  A_ptr[m+1] must contain ne+1 that indicates the position after the
+*  last element in the arrays A_ind and A_val.
+* 
+*  A_ind is an integer array of length [1+ne]. Location A_ind[0] is not
+*  used, and locations A_ind[1], ..., A_ind[ne] contain column indices
+*  of (non-zero) elements in matrix A.
+*
+*  A_val is a floating-point array of length [1+ne]. Location A_val[0]
+*  is not used, and locations A_val[1], ..., A_val[ne] contain numeric
+*  values of non-zero elements in matrix A.
+* 
+*  Non-zero elements of matrix A are stored contiguously, and the rows
+*  of matrix A are stored consecutively from 1 to m in the arrays A_ind
+*  and A_val. The elements in each row of A may be stored in any order
+*  in A_ind and A_val. Note that elements with duplicate column indices
+*  are not allowed.
+* 
+*  Let, for example, the following sparse matrix A be given:
+* 
+*     | 11  . 13  .  .  . |
+*     | 21 22  . 24  .  . |
+*     |  . 32 33  .  .  . |
+*     |  .  . 43 44  . 46 |
+*     |  .  .  .  .  .  . |
+*     | 61 62  .  .  . 66 |
+* 
+*  Then the arrays are:
+* 
+*     A_ptr = { X; 1, 3, 6, 8, 11, 11; 14 }
+*
+*     A_ind = { X;  1,  3;  4,  2,  1;  2,  3;  4,  3,  6;  1,  2,  6 }
+* 
+*     A_val = { X; 11, 13; 24, 22, 21; 32, 33; 44, 43, 46; 61, 62, 66 }
+* 
+*  PERMUTATION MATRICES
+* 
+*  Let P be a permutation matrix of the order n. It is represented as
+*  an integer array P_per of length [1+n+n] as follows: if p[i,j] = 1,
+*  then P_per[i] = j and P_per[n+j] = i. Location P_per[0] is not used.
+* 
+*  Let A' = P*A. If i-th row of A corresponds to i'-th row of A', then
+*  P_per[i'] = i and P_per[n+i] = i'.
+* 
+*  References:
+* 
+*  1. Gustavson F.G. Some basic techniques for solving sparse systems of
+*     linear equations. In Rose and Willoughby (1972), pp. 41-52.
+* 
+*  2. Basic Linear Algebra Subprograms Technical (BLAST) Forum Standard.
+*     University of Tennessee (2001). */
+
+#define check_fvs _glp_mat_check_fvs
+int check_fvs(int n, int nnz, int ind[], double vec[]);
+/* check sparse vector in full-vector storage format */
+
+#define check_pattern _glp_mat_check_pattern
+int check_pattern(int m, int n, int A_ptr[], int A_ind[]);
+/* check pattern of sparse matrix */
+
+#define transpose _glp_mat_transpose
+void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[],
+      int AT_ptr[], int AT_ind[], double AT_val[]);
+/* transpose sparse matrix */
+
+#define adat_symbolic _glp_mat_adat_symbolic
+int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[],
+      int S_ptr[]);
+/* compute S = P*A*D*A'*P' (symbolic phase) */
+
+#define adat_numeric _glp_mat_adat_numeric
+void adat_numeric(int m, int n, int P_per[],
+      int A_ptr[], int A_ind[], double A_val[], double D_diag[],
+      int S_ptr[], int S_ind[], double S_val[], double S_diag[]);
+/* compute S = P*A*D*A'*P' (numeric phase) */
+
+#define min_degree _glp_mat_min_degree
+void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* minimum degree ordering */
+
+#define amd_order1 _glp_mat_amd_order1
+void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* approximate minimum degree ordering (AMD) */
+
+#define symamd_ord _glp_mat_symamd_ord
+void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[]);
+/* approximate minimum degree ordering (SYMAMD) */
+
+#define chol_symbolic _glp_mat_chol_symbolic
+int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]);
+/* compute Cholesky factorization (symbolic phase) */
+
+#define chol_numeric _glp_mat_chol_numeric
+int chol_numeric(int n,
+      int A_ptr[], int A_ind[], double A_val[], double A_diag[],
+      int U_ptr[], int U_ind[], double U_val[], double U_diag[]);
+/* compute Cholesky factorization (numeric phase) */
+
+#define u_solve _glp_mat_u_solve
+void u_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[]);
+/* solve upper triangular system U*x = b */
+
+#define ut_solve _glp_mat_ut_solve
+void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[],
+      double U_diag[], double x[]);
+/* solve lower triangular system U'*x = b */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpmpl.h
===================================================================
--- deps/glpk/src/glpmpl.h	(revision 9)
+++ deps/glpk/src/glpmpl.h	(revision 9)
@@ -0,0 +1,2583 @@
+/* glpmpl.h (GNU MathProg translator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPMPL_H
+#define GLPMPL_H
+
+#include "glpavl.h"
+#include "glprng.h"
+
+typedef struct MPL MPL;
+typedef char STRING;
+typedef struct SYMBOL SYMBOL;
+typedef struct TUPLE TUPLE;
+typedef struct ARRAY ELEMSET;
+typedef struct ELEMVAR ELEMVAR;
+typedef struct FORMULA FORMULA;
+typedef struct ELEMCON ELEMCON;
+typedef union VALUE VALUE;
+typedef struct ARRAY ARRAY;
+typedef struct MEMBER MEMBER;
+#if 1
+/* many C compilers have DOMAIN declared in <math.h> :( */
+#undef DOMAIN
+#define DOMAIN DOMAIN1
+#endif
+typedef struct DOMAIN DOMAIN;
+typedef struct DOMAIN_BLOCK DOMAIN_BLOCK;
+typedef struct DOMAIN_SLOT DOMAIN_SLOT;
+typedef struct SET SET;
+typedef struct WITHIN WITHIN;
+typedef struct GADGET GADGET;
+typedef struct PARAMETER PARAMETER;
+typedef struct CONDITION CONDITION;
+typedef struct VARIABLE VARIABLE;
+typedef struct CONSTRAINT CONSTRAINT;
+typedef struct TABLE TABLE;
+typedef struct TABARG TABARG;
+typedef struct TABFLD TABFLD;
+typedef struct TABIN TABIN;
+typedef struct TABOUT TABOUT;
+typedef struct TABDCA TABDCA;
+typedef union OPERANDS OPERANDS;
+typedef struct ARG_LIST ARG_LIST;
+typedef struct CODE CODE;
+typedef struct CHECK CHECK;
+typedef struct DISPLAY DISPLAY;
+typedef struct DISPLAY1 DISPLAY1;
+typedef struct PRINTF PRINTF;
+typedef struct PRINTF1 PRINTF1;
+typedef struct FOR FOR;
+typedef struct STATEMENT STATEMENT;
+typedef struct TUPLE SLICE;
+
+/**********************************************************************/
+/* * *                    TRANSLATOR DATABASE                     * * */
+/**********************************************************************/
+
+#define A_BINARY        101   /* something binary */
+#define A_CHECK         102   /* check statement */
+#define A_CONSTRAINT    103   /* model constraint */
+#define A_DISPLAY       104   /* display statement */
+#define A_ELEMCON       105   /* elemental constraint/objective */
+#define A_ELEMSET       106   /* elemental set */
+#define A_ELEMVAR       107   /* elemental variable */
+#define A_EXPRESSION    108   /* expression */
+#define A_FOR           109   /* for statement */
+#define A_FORMULA       110   /* formula */
+#define A_INDEX         111   /* dummy index */
+#define A_INPUT         112   /* input table */
+#define A_INTEGER       113   /* something integer */
+#define A_LOGICAL       114   /* something logical */
+#define A_MAXIMIZE      115   /* objective has to be maximized */
+#define A_MINIMIZE      116   /* objective has to be minimized */
+#define A_NONE          117   /* nothing */
+#define A_NUMERIC       118   /* something numeric */
+#define A_OUTPUT        119   /* output table */
+#define A_PARAMETER     120   /* model parameter */
+#define A_PRINTF        121   /* printf statement */
+#define A_SET           122   /* model set */
+#define A_SOLVE         123   /* solve statement */
+#define A_SYMBOLIC      124   /* something symbolic */
+#define A_TABLE         125   /* data table */
+#define A_TUPLE         126   /* n-tuple */
+#define A_VARIABLE      127   /* model variable */
+
+#define MAX_LENGTH 100
+/* maximal length of any symbolic value (this includes symbolic names,
+   numeric and string literals, and all symbolic values that may appear
+   during the evaluation phase) */
+
+#define CONTEXT_SIZE 60
+/* size of the context queue, in characters */
+
+#define OUTBUF_SIZE 1024
+/* size of the output buffer, in characters */
+
+struct MPL
+{     /* translator database */
+      /*--------------------------------------------------------------*/
+      /* scanning segment */
+      int line;
+      /* number of the current text line */
+      int c;
+      /* the current character or EOF */
+      int token;
+      /* the current token: */
+#define T_EOF           201   /* end of file */
+#define T_NAME          202   /* symbolic name (model section only) */
+#define T_SYMBOL        203   /* symbol (data section only) */
+#define T_NUMBER        204   /* numeric literal */
+#define T_STRING        205   /* string literal */
+#define T_AND           206   /* and && */
+#define T_BY            207   /* by */
+#define T_CROSS         208   /* cross */
+#define T_DIFF          209   /* diff */
+#define T_DIV           210   /* div */
+#define T_ELSE          211   /* else */
+#define T_IF            212   /* if */
+#define T_IN            213   /* in */
+#define T_INFINITY      214   /* Infinity */
+#define T_INTER         215   /* inter */
+#define T_LESS          216   /* less */
+#define T_MOD           217   /* mod */
+#define T_NOT           218   /* not ! */
+#define T_OR            219   /* or || */
+#define T_SPTP          220   /* s.t. */
+#define T_SYMDIFF       221   /* symdiff */
+#define T_THEN          222   /* then */
+#define T_UNION         223   /* union */
+#define T_WITHIN        224   /* within */
+#define T_PLUS          225   /* + */
+#define T_MINUS         226   /* - */
+#define T_ASTERISK      227   /* * */
+#define T_SLASH         228   /* / */
+#define T_POWER         229   /* ^ ** */
+#define T_LT            230   /* <  */
+#define T_LE            231   /* <= */
+#define T_EQ            232   /* = == */
+#define T_GE            233   /* >= */
+#define T_GT            234   /* >  */
+#define T_NE            235   /* <> != */
+#define T_CONCAT        236   /* & */
+#define T_BAR           237   /* | */
+#define T_POINT         238   /* . */
+#define T_COMMA         239   /* , */
+#define T_COLON         240   /* : */
+#define T_SEMICOLON     241   /* ; */
+#define T_ASSIGN        242   /* := */
+#define T_DOTS          243   /* .. */
+#define T_LEFT          244   /* ( */
+#define T_RIGHT         245   /* ) */
+#define T_LBRACKET      246   /* [ */
+#define T_RBRACKET      247   /* ] */
+#define T_LBRACE        248   /* { */
+#define T_RBRACE        249   /* } */
+#define T_APPEND        250   /* >> */
+#define T_TILDE         251   /* ~ */
+#define T_INPUT         252   /* <- */
+      int imlen;
+      /* length of the current token */
+      char *image; /* char image[MAX_LENGTH+1]; */
+      /* image of the current token */
+      double value;
+      /* value of the current token (for T_NUMBER only) */
+      int b_token;
+      /* the previous token */
+      int b_imlen;
+      /* length of the previous token */
+      char *b_image; /* char b_image[MAX_LENGTH+1]; */
+      /* image of the previous token */
+      double b_value;
+      /* value of the previous token (if token is T_NUMBER) */
+      int f_dots;
+      /* if this flag is set, the next token should be recognized as
+         T_DOTS, not as T_POINT */
+      int f_scan;
+      /* if this flag is set, the next token is already scanned */
+      int f_token;
+      /* the next token */
+      int f_imlen;
+      /* length of the next token */
+      char *f_image; /* char f_image[MAX_LENGTH+1]; */
+      /* image of the next token */
+      double f_value;
+      /* value of the next token (if token is T_NUMBER) */
+      char *context; /* char context[CONTEXT_SIZE]; */
+      /* context circular queue (not null-terminated!) */
+      int c_ptr;
+      /* pointer to the current position in the context queue */
+      int flag_d;
+      /* if this flag is set, the data section is being processed */
+      /*--------------------------------------------------------------*/
+      /* translating segment */
+      DMP *pool;
+      /* memory pool used to allocate all data instances created during
+         the translation phase */
+      AVL *tree;
+      /* symbolic name table:
+         node.type = A_INDEX     => node.link -> DOMAIN_SLOT
+         node.type = A_SET       => node.link -> SET
+         node.type = A_PARAMETER => node.link -> PARAMETER
+         node.type = A_VARIABLE  => node.link -> VARIABLE
+         node.type = A_CONSTRANT => node.link -> CONSTRAINT */
+      STATEMENT *model;
+      /* linked list of model statements in the original order */
+      int flag_x;
+      /* if this flag is set, the current token being left parenthesis
+         begins a slice that allows recognizing any undeclared symbolic
+         names as dummy indices; this flag is automatically reset once
+         the next token has been scanned */
+      int as_within;
+      /* the warning "in understood as within" has been issued */
+      int as_in;
+      /* the warning "within understood as in" has been issued */
+      int as_binary;
+      /* the warning "logical understood as binary" has been issued */
+      int flag_s;
+      /* if this flag is set, the solve statement has been parsed */
+      /*--------------------------------------------------------------*/
+      /* common segment */
+      DMP *strings;
+      /* memory pool to allocate STRING data structures */
+      DMP *symbols;
+      /* memory pool to allocate SYMBOL data structures */
+      DMP *tuples;
+      /* memory pool to allocate TUPLE data structures */
+      DMP *arrays;
+      /* memory pool to allocate ARRAY data structures */
+      DMP *members;
+      /* memory pool to allocate MEMBER data structures */
+      DMP *elemvars;
+      /* memory pool to allocate ELEMVAR data structures */
+      DMP *formulae;
+      /* memory pool to allocate FORMULA data structures */
+      DMP *elemcons;
+      /* memory pool to allocate ELEMCON data structures */
+      ARRAY *a_list;
+      /* linked list of all arrays in the database */
+      char *sym_buf; /* char sym_buf[255+1]; */
+      /* working buffer used by the routine format_symbol */
+      char *tup_buf; /* char tup_buf[255+1]; */
+      /* working buffer used by the routine format_tuple */
+      /*--------------------------------------------------------------*/
+      /* generating/postsolving segment */
+      RNG *rand;
+      /* pseudo-random number generator */
+      int flag_p;
+      /* if this flag is set, the postsolving phase is in effect */
+      STATEMENT *stmt;
+      /* model statement being currently executed */
+      TABDCA *dca;
+      /* pointer to table driver communication area for table statement
+         currently executed */
+      int m;
+      /* number of rows in the problem, m >= 0 */
+      int n;
+      /* number of columns in the problem, n >= 0 */
+      ELEMCON **row; /* ELEMCON *row[1+m]; */
+      /* row[0] is not used;
+         row[i] is elemental constraint or objective, which corresponds
+         to i-th row of the problem, 1 <= i <= m */
+      ELEMVAR **col; /* ELEMVAR *col[1+n]; */
+      /* col[0] is not used;
+         col[j] is elemental variable, which corresponds to j-th column
+         of the problem, 1 <= j <= n */
+      /*--------------------------------------------------------------*/
+      /* input/output segment */
+      XFILE *in_fp;
+      /* stream assigned to the input text file */
+      char *in_file;
+      /* name of the input text file */
+      XFILE *out_fp;
+      /* stream assigned to the output text file used to write all data
+         produced by display and printf statements; NULL means the data
+         should be sent to stdout via the routine xprintf */
+      char *out_file;
+      /* name of the output text file */
+#if 0 /* 08/XI-2009 */
+      char *out_buf; /* char out_buf[OUTBUF_SIZE] */
+      /* buffer to accumulate output data */
+      int out_cnt;
+      /* count of data bytes stored in the output buffer */
+#endif
+      XFILE *prt_fp;
+      /* stream assigned to the print text file; may be NULL */
+      char *prt_file;
+      /* name of the output print file */
+      /*--------------------------------------------------------------*/
+      /* solver interface segment */
+      jmp_buf jump;
+      /* jump address for non-local go to in case of error */
+      int phase;
+      /* phase of processing:
+         0 - database is being or has been initialized
+         1 - model section is being or has been read
+         2 - data section is being or has been read
+         3 - model is being or has been generated/postsolved
+         4 - model processing error has occurred */
+      char *mod_file;
+      /* name of the input text file, which contains model section */
+      char *mpl_buf; /* char mpl_buf[255+1]; */
+      /* working buffer used by some interface routines */
+};
+
+/**********************************************************************/
+/* * *                  PROCESSING MODEL SECTION                  * * */
+/**********************************************************************/
+
+#define alloc(type) ((type *)dmp_get_atomv(mpl->pool, sizeof(type)))
+/* allocate atom of given type */
+
+#define enter_context _glp_mpl_enter_context
+void enter_context(MPL *mpl);
+/* enter current token into context queue */
+
+#define print_context _glp_mpl_print_context
+void print_context(MPL *mpl);
+/* print current content of context queue */
+
+#define get_char _glp_mpl_get_char
+void get_char(MPL *mpl);
+/* scan next character from input text file */
+
+#define append_char _glp_mpl_append_char
+void append_char(MPL *mpl);
+/* append character to current token */
+
+#define get_token _glp_mpl_get_token
+void get_token(MPL *mpl);
+/* scan next token from input text file */
+
+#define unget_token _glp_mpl_unget_token
+void unget_token(MPL *mpl);
+/* return current token back to input stream */
+
+#define is_keyword _glp_mpl_is_keyword
+int is_keyword(MPL *mpl, char *keyword);
+/* check if current token is given non-reserved keyword */
+
+#define is_reserved _glp_mpl_is_reserved
+int is_reserved(MPL *mpl);
+/* check if current token is reserved keyword */
+
+#define make_code _glp_mpl_make_code
+CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim);
+/* generate pseudo-code (basic routine) */
+
+#define make_unary _glp_mpl_make_unary
+CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim);
+/* generate pseudo-code for unary operation */
+
+#define make_binary _glp_mpl_make_binary
+CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
+      int dim);
+/* generate pseudo-code for binary operation */
+
+#define make_ternary _glp_mpl_make_ternary
+CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
+      int type, int dim);
+/* generate pseudo-code for ternary operation */
+
+#define numeric_literal _glp_mpl_numeric_literal
+CODE *numeric_literal(MPL *mpl);
+/* parse reference to numeric literal */
+
+#define string_literal _glp_mpl_string_literal
+CODE *string_literal(MPL *mpl);
+/* parse reference to string literal */
+
+#define create_arg_list _glp_mpl_create_arg_list
+ARG_LIST *create_arg_list(MPL *mpl);
+/* create empty operands list */
+
+#define expand_arg_list _glp_mpl_expand_arg_list
+ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x);
+/* append operand to operands list */
+
+#define arg_list_len _glp_mpl_arg_list_len
+int arg_list_len(MPL *mpl, ARG_LIST *list);
+/* determine length of operands list */
+
+#define subscript_list _glp_mpl_subscript_list
+ARG_LIST *subscript_list(MPL *mpl);
+/* parse subscript list */
+
+#define object_reference _glp_mpl_object_reference
+CODE *object_reference(MPL *mpl);
+/* parse reference to named object */
+
+#define numeric_argument _glp_mpl_numeric_argument
+CODE *numeric_argument(MPL *mpl, char *func);
+/* parse argument passed to built-in function */
+
+#define symbolic_argument _glp_mpl_symbolic_argument
+CODE *symbolic_argument(MPL *mpl, char *func);
+
+#define elemset_argument _glp_mpl_elemset_argument
+CODE *elemset_argument(MPL *mpl, char *func);
+
+#define function_reference _glp_mpl_function_reference
+CODE *function_reference(MPL *mpl);
+/* parse reference to built-in function */
+
+#define create_domain _glp_mpl_create_domain
+DOMAIN *create_domain(MPL *mpl);
+/* create empty domain */
+
+#define create_block _glp_mpl_create_block
+DOMAIN_BLOCK *create_block(MPL *mpl);
+/* create empty domain block */
+
+#define append_block _glp_mpl_append_block
+void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block);
+/* append domain block to specified domain */
+
+#define append_slot _glp_mpl_append_slot
+DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
+      CODE *code);
+/* create and append new slot to domain block */
+
+#define expression_list _glp_mpl_expression_list
+CODE *expression_list(MPL *mpl);
+/* parse expression list */
+
+#define literal_set _glp_mpl_literal_set
+CODE *literal_set(MPL *mpl, CODE *code);
+/* parse literal set */
+
+#define indexing_expression _glp_mpl_indexing_expression
+DOMAIN *indexing_expression(MPL *mpl);
+/* parse indexing expression */
+
+#define close_scope _glp_mpl_close_scope
+void close_scope(MPL *mpl, DOMAIN *domain);
+/* close scope of indexing expression */
+
+#define iterated_expression _glp_mpl_iterated_expression
+CODE *iterated_expression(MPL *mpl);
+/* parse iterated expression */
+
+#define domain_arity _glp_mpl_domain_arity
+int domain_arity(MPL *mpl, DOMAIN *domain);
+/* determine arity of domain */
+
+#define set_expression _glp_mpl_set_expression
+CODE *set_expression(MPL *mpl);
+/* parse set expression */
+
+#define branched_expression _glp_mpl_branched_expression
+CODE *branched_expression(MPL *mpl);
+/* parse conditional expression */
+
+#define primary_expression _glp_mpl_primary_expression
+CODE *primary_expression(MPL *mpl);
+/* parse primary expression */
+
+#define error_preceding _glp_mpl_error_preceding
+void error_preceding(MPL *mpl, char *opstr);
+/* raise error if preceding operand has wrong type */
+
+#define error_following _glp_mpl_error_following
+void error_following(MPL *mpl, char *opstr);
+/* raise error if following operand has wrong type */
+
+#define error_dimension _glp_mpl_error_dimension
+void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2);
+/* raise error if operands have different dimension */
+
+#define expression_0 _glp_mpl_expression_0
+CODE *expression_0(MPL *mpl);
+/* parse expression of level 0 */
+
+#define expression_1 _glp_mpl_expression_1
+CODE *expression_1(MPL *mpl);
+/* parse expression of level 1 */
+
+#define expression_2 _glp_mpl_expression_2
+CODE *expression_2(MPL *mpl);
+/* parse expression of level 2 */
+
+#define expression_3 _glp_mpl_expression_3
+CODE *expression_3(MPL *mpl);
+/* parse expression of level 3 */
+
+#define expression_4 _glp_mpl_expression_4
+CODE *expression_4(MPL *mpl);
+/* parse expression of level 4 */
+
+#define expression_5 _glp_mpl_expression_5
+CODE *expression_5(MPL *mpl);
+/* parse expression of level 5 */
+
+#define expression_6 _glp_mpl_expression_6
+CODE *expression_6(MPL *mpl);
+/* parse expression of level 6 */
+
+#define expression_7 _glp_mpl_expression_7
+CODE *expression_7(MPL *mpl);
+/* parse expression of level 7 */
+
+#define expression_8 _glp_mpl_expression_8
+CODE *expression_8(MPL *mpl);
+/* parse expression of level 8 */
+
+#define expression_9 _glp_mpl_expression_9
+CODE *expression_9(MPL *mpl);
+/* parse expression of level 9 */
+
+#define expression_10 _glp_mpl_expression_10
+CODE *expression_10(MPL *mpl);
+/* parse expression of level 10 */
+
+#define expression_11 _glp_mpl_expression_11
+CODE *expression_11(MPL *mpl);
+/* parse expression of level 11 */
+
+#define expression_12 _glp_mpl_expression_12
+CODE *expression_12(MPL *mpl);
+/* parse expression of level 12 */
+
+#define expression_13 _glp_mpl_expression_13
+CODE *expression_13(MPL *mpl);
+/* parse expression of level 13 */
+
+#define set_statement _glp_mpl_set_statement
+SET *set_statement(MPL *mpl);
+/* parse set statement */
+
+#define parameter_statement _glp_mpl_parameter_statement
+PARAMETER *parameter_statement(MPL *mpl);
+/* parse parameter statement */
+
+#define variable_statement _glp_mpl_variable_statement
+VARIABLE *variable_statement(MPL *mpl);
+/* parse variable statement */
+
+#define constraint_statement _glp_mpl_constraint_statement
+CONSTRAINT *constraint_statement(MPL *mpl);
+/* parse constraint statement */
+
+#define objective_statement _glp_mpl_objective_statement
+CONSTRAINT *objective_statement(MPL *mpl);
+/* parse objective statement */
+
+#define table_statement _glp_mpl_table_statement
+TABLE *table_statement(MPL *mpl);
+/* parse table statement */
+
+#define solve_statement _glp_mpl_solve_statement
+void *solve_statement(MPL *mpl);
+/* parse solve statement */
+
+#define check_statement _glp_mpl_check_statement
+CHECK *check_statement(MPL *mpl);
+/* parse check statement */
+
+#define display_statement _glp_mpl_display_statement
+DISPLAY *display_statement(MPL *mpl);
+/* parse display statement */
+
+#define printf_statement _glp_mpl_printf_statement
+PRINTF *printf_statement(MPL *mpl);
+/* parse printf statement */
+
+#define for_statement _glp_mpl_for_statement
+FOR *for_statement(MPL *mpl);
+/* parse for statement */
+
+#define end_statement _glp_mpl_end_statement
+void end_statement(MPL *mpl);
+/* parse end statement */
+
+#define simple_statement _glp_mpl_simple_statement
+STATEMENT *simple_statement(MPL *mpl, int spec);
+/* parse simple statement */
+
+#define model_section _glp_mpl_model_section
+void model_section(MPL *mpl);
+/* parse model section */
+
+/**********************************************************************/
+/* * *                  PROCESSING DATA SECTION                   * * */
+/**********************************************************************/
+
+#if 2 + 2 == 5
+struct SLICE /* see TUPLE */
+{     /* component of slice; the slice itself is associated with its
+         first component; slices are similar to n-tuples with exception
+         that some slice components (which are indicated by asterisks)
+         don't refer to any symbols */
+      SYMBOL *sym;
+      /* symbol, which this component refers to; can be NULL */
+      SLICE *next;
+      /* the next component of slice */
+};
+#endif
+
+#define create_slice _glp_mpl_create_slice
+SLICE *create_slice(MPL *mpl);
+/* create slice */
+
+#define expand_slice _glp_mpl_expand_slice
+SLICE *expand_slice
+(     MPL *mpl,
+      SLICE *slice,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+);
+/* append new component to slice */
+
+#define slice_dimen _glp_mpl_slice_dimen
+int slice_dimen
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+);
+/* determine dimension of slice */
+
+#define slice_arity _glp_mpl_slice_arity
+int slice_arity
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+);
+/* determine arity of slice */
+
+#define fake_slice _glp_mpl_fake_slice
+SLICE *fake_slice(MPL *mpl, int dim);
+/* create fake slice of all asterisks */
+
+#define delete_slice _glp_mpl_delete_slice
+void delete_slice
+(     MPL *mpl,
+      SLICE *slice            /* destroyed */
+);
+/* delete slice */
+
+#define is_number _glp_mpl_is_number
+int is_number(MPL *mpl);
+/* check if current token is number */
+
+#define is_symbol _glp_mpl_is_symbol
+int is_symbol(MPL *mpl);
+/* check if current token is symbol */
+
+#define is_literal _glp_mpl_is_literal
+int is_literal(MPL *mpl, char *literal);
+/* check if current token is given symbolic literal */
+
+#define read_number _glp_mpl_read_number
+double read_number(MPL *mpl);
+/* read number */
+
+#define read_symbol _glp_mpl_read_symbol
+SYMBOL *read_symbol(MPL *mpl);
+/* read symbol */
+
+#define read_slice _glp_mpl_read_slice
+SLICE *read_slice
+(     MPL *mpl,
+      char *name,             /* not changed */
+      int dim
+);
+/* read slice */
+
+#define select_set _glp_mpl_select_set
+SET *select_set
+(     MPL *mpl,
+      char *name              /* not changed */
+);
+/* select set to saturate it with elemental sets */
+
+#define simple_format _glp_mpl_simple_format
+void simple_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice            /* not changed */
+);
+/* read set data block in simple format */
+
+#define matrix_format _glp_mpl_matrix_format
+void matrix_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice,           /* not changed */
+      int tr
+);
+/* read set data block in matrix format */
+
+#define set_data _glp_mpl_set_data
+void set_data(MPL *mpl);
+/* read set data */
+
+#define select_parameter _glp_mpl_select_parameter
+PARAMETER *select_parameter
+(     MPL *mpl,
+      char *name              /* not changed */
+);
+/* select parameter to saturate it with data */
+
+#define set_default _glp_mpl_set_default
+void set_default
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SYMBOL *altval          /* destroyed */
+);
+/* set default parameter value */
+
+#define read_value _glp_mpl_read_value
+MEMBER *read_value
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* destroyed */
+);
+/* read value and assign it to parameter member */
+
+#define plain_format _glp_mpl_plain_format
+void plain_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice            /* not changed */
+);
+/* read parameter data block in plain format */
+
+#define tabular_format _glp_mpl_tabular_format
+void tabular_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice,           /* not changed */
+      int tr
+);
+/* read parameter data block in tabular format */
+
+#define tabbing_format _glp_mpl_tabbing_format
+void tabbing_format
+(     MPL *mpl,
+      SYMBOL *altval          /* not changed */
+);
+/* read parameter data block in tabbing format */
+
+#define parameter_data _glp_mpl_parameter_data
+void parameter_data(MPL *mpl);
+/* read parameter data */
+
+#define data_section _glp_mpl_data_section
+void data_section(MPL *mpl);
+/* read data section */
+
+/**********************************************************************/
+/* * *                   FLOATING-POINT NUMBERS                   * * */
+/**********************************************************************/
+
+#define fp_add _glp_mpl_fp_add
+double fp_add(MPL *mpl, double x, double y);
+/* floating-point addition */
+
+#define fp_sub _glp_mpl_fp_sub
+double fp_sub(MPL *mpl, double x, double y);
+/* floating-point subtraction */
+
+#define fp_less _glp_mpl_fp_less
+double fp_less(MPL *mpl, double x, double y);
+/* floating-point non-negative subtraction */
+
+#define fp_mul _glp_mpl_fp_mul
+double fp_mul(MPL *mpl, double x, double y);
+/* floating-point multiplication */
+
+#define fp_div _glp_mpl_fp_div
+double fp_div(MPL *mpl, double x, double y);
+/* floating-point division */
+
+#define fp_idiv _glp_mpl_fp_idiv
+double fp_idiv(MPL *mpl, double x, double y);
+/* floating-point quotient of exact division */
+
+#define fp_mod _glp_mpl_fp_mod
+double fp_mod(MPL *mpl, double x, double y);
+/* floating-point remainder of exact division */
+
+#define fp_power _glp_mpl_fp_power
+double fp_power(MPL *mpl, double x, double y);
+/* floating-point exponentiation (raise to power) */
+
+#define fp_exp _glp_mpl_fp_exp
+double fp_exp(MPL *mpl, double x);
+/* floating-point base-e exponential */
+
+#define fp_log _glp_mpl_fp_log
+double fp_log(MPL *mpl, double x);
+/* floating-point natural logarithm */
+
+#define fp_log10 _glp_mpl_fp_log10
+double fp_log10(MPL *mpl, double x);
+/* floating-point common (decimal) logarithm */
+
+#define fp_sqrt _glp_mpl_fp_sqrt
+double fp_sqrt(MPL *mpl, double x);
+/* floating-point square root */
+
+#define fp_sin _glp_mpl_fp_sin
+double fp_sin(MPL *mpl, double x);
+/* floating-point trigonometric sine */
+
+#define fp_cos _glp_mpl_fp_cos
+double fp_cos(MPL *mpl, double x);
+/* floating-point trigonometric cosine */
+
+#define fp_atan _glp_mpl_fp_atan
+double fp_atan(MPL *mpl, double x);
+/* floating-point trigonometric arctangent */
+
+#define fp_atan2 _glp_mpl_fp_atan2
+double fp_atan2(MPL *mpl, double y, double x);
+/* floating-point trigonometric arctangent */
+
+#define fp_round _glp_mpl_fp_round
+double fp_round(MPL *mpl, double x, double n);
+/* round floating-point value to n fractional digits */
+
+#define fp_trunc _glp_mpl_fp_trunc
+double fp_trunc(MPL *mpl, double x, double n);
+/* truncate floating-point value to n fractional digits */
+
+/**********************************************************************/
+/* * *              PSEUDO-RANDOM NUMBER GENERATORS               * * */
+/**********************************************************************/
+
+#define fp_irand224 _glp_mpl_fp_irand224
+double fp_irand224(MPL *mpl);
+/* pseudo-random integer in the range [0, 2^24) */
+
+#define fp_uniform01 _glp_mpl_fp_uniform01
+double fp_uniform01(MPL *mpl);
+/* pseudo-random number in the range [0, 1) */
+
+#define fp_uniform _glp_mpl_uniform
+double fp_uniform(MPL *mpl, double a, double b);
+/* pseudo-random number in the range [a, b) */
+
+#define fp_normal01 _glp_mpl_fp_normal01
+double fp_normal01(MPL *mpl);
+/* Gaussian random variate with mu = 0 and sigma = 1 */
+
+#define fp_normal _glp_mpl_fp_normal
+double fp_normal(MPL *mpl, double mu, double sigma);
+/* Gaussian random variate with specified mu and sigma */
+
+/**********************************************************************/
+/* * *                         DATE/TIME                          * * */
+/**********************************************************************/
+
+#define fn_gmtime _glp_mpl_fn_gmtime
+double fn_gmtime(MPL *mpl);
+/* obtain the current calendar time (UTC) */
+
+#define fn_str2time _glp_mpl_fn_str2time
+double fn_str2time(MPL *mpl, const char *str, const char *fmt);
+/* convert character string to the calendar time */
+
+#define fn_time2str _glp_mpl_fn_time2str
+void fn_time2str(MPL *mpl, char *str, double t, const char *fmt);
+/* convert the calendar time to character string */
+
+/**********************************************************************/
+/* * *                     CHARACTER STRINGS                      * * */
+/**********************************************************************/
+
+#define create_string _glp_mpl_create_string
+STRING *create_string
+(     MPL *mpl,
+      char buf[MAX_LENGTH+1]  /* not changed */
+);
+/* create character string */
+
+#define copy_string _glp_mpl_copy_string
+STRING *copy_string
+(     MPL *mpl,
+      STRING *str             /* not changed */
+);
+/* make copy of character string */
+
+#define compare_strings _glp_mpl_compare_strings
+int compare_strings
+(     MPL *mpl,
+      STRING *str1,           /* not changed */
+      STRING *str2            /* not changed */
+);
+/* compare one character string with another */
+
+#define fetch_string _glp_mpl_fetch_string
+char *fetch_string
+(     MPL *mpl,
+      STRING *str,            /* not changed */
+      char buf[MAX_LENGTH+1]  /* modified */
+);
+/* extract content of character string */
+
+#define delete_string _glp_mpl_delete_string
+void delete_string
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+);
+/* delete character string */
+
+/**********************************************************************/
+/* * *                          SYMBOLS                           * * */
+/**********************************************************************/
+
+struct SYMBOL
+{     /* symbol (numeric or abstract quantity) */
+      double num;
+      /* numeric value of symbol (used only if str == NULL) */
+      STRING *str;
+      /* abstract value of symbol (used only if str != NULL) */
+};
+
+#define create_symbol_num _glp_mpl_create_symbol_num
+SYMBOL *create_symbol_num(MPL *mpl, double num);
+/* create symbol of numeric type */
+
+#define create_symbol_str _glp_mpl_create_symbol_str
+SYMBOL *create_symbol_str
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+);
+/* create symbol of abstract type */
+
+#define copy_symbol _glp_mpl_copy_symbol
+SYMBOL *copy_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+);
+/* make copy of symbol */
+
+#define compare_symbols _glp_mpl_compare_symbols
+int compare_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* not changed */
+      SYMBOL *sym2            /* not changed */
+);
+/* compare one symbol with another */
+
+#define delete_symbol _glp_mpl_delete_symbol
+void delete_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* destroyed */
+);
+/* delete symbol */
+
+#define format_symbol _glp_mpl_format_symbol
+char *format_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+);
+/* format symbol for displaying or printing */
+
+#define concat_symbols _glp_mpl_concat_symbols
+SYMBOL *concat_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* destroyed */
+      SYMBOL *sym2            /* destroyed */
+);
+/* concatenate one symbol with another */
+
+/**********************************************************************/
+/* * *                          N-TUPLES                          * * */
+/**********************************************************************/
+
+struct TUPLE
+{     /* component of n-tuple; the n-tuple itself is associated with
+         its first component; (note that 0-tuple has no components) */
+      SYMBOL *sym;
+      /* symbol, which the component refers to; cannot be NULL */
+      TUPLE *next;
+      /* the next component of n-tuple */
+};
+
+#define create_tuple _glp_mpl_create_tuple
+TUPLE *create_tuple(MPL *mpl);
+/* create n-tuple */
+
+#define expand_tuple _glp_mpl_expand_tuple
+TUPLE *expand_tuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+);
+/* append symbol to n-tuple */
+
+#define tuple_dimen _glp_mpl_tuple_dimen
+int tuple_dimen
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+);
+/* determine dimension of n-tuple */
+
+#define copy_tuple _glp_mpl_copy_tuple
+TUPLE *copy_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+);
+/* make copy of n-tuple */
+
+#define compare_tuples _glp_mpl_compare_tuples
+int compare_tuples
+(     MPL *mpl,
+      TUPLE *tuple1,          /* not changed */
+      TUPLE *tuple2           /* not changed */
+);
+/* compare one n-tuple with another */
+
+#define build_subtuple _glp_mpl_build_subtuple
+TUPLE *build_subtuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* not changed */
+      int dim
+);
+/* build subtuple of given n-tuple */
+
+#define delete_tuple _glp_mpl_delete_tuple
+void delete_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* destroyed */
+);
+/* delete n-tuple */
+
+#define format_tuple _glp_mpl_format_tuple
+char *format_tuple
+(     MPL *mpl,
+      int c,
+      TUPLE *tuple            /* not changed */
+);
+/* format n-tuple for displaying or printing */
+
+/**********************************************************************/
+/* * *                       ELEMENTAL SETS                       * * */
+/**********************************************************************/
+
+#if 2 + 2 == 5
+struct ELEMSET /* see ARRAY */
+{     /* elemental set of n-tuples; formally it is a "value" assigned
+         to members of model sets (like numbers and symbols, which are
+         values assigned to members of model parameters); note that a
+         simple model set is not an elemental set, it is 0-dimensional
+         array, the only member of which (if it exists) is assigned an
+         elemental set */
+#endif
+
+#define create_elemset _glp_mpl_create_elemset
+ELEMSET *create_elemset(MPL *mpl, int dim);
+/* create elemental set */
+
+#define find_tuple _glp_mpl_find_tuple
+MEMBER *find_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* check if elemental set contains given n-tuple */
+
+#define add_tuple _glp_mpl_add_tuple
+MEMBER *add_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+);
+/* add new n-tuple to elemental set */
+
+#define check_then_add _glp_mpl_check_then_add
+MEMBER *check_then_add
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+);
+/* check and add new n-tuple to elemental set */
+
+#define copy_elemset _glp_mpl_copy_elemset
+ELEMSET *copy_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* not changed */
+);
+/* make copy of elemental set */
+
+#define delete_elemset _glp_mpl_delete_elemset
+void delete_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* destroyed */
+);
+/* delete elemental set */
+
+#define arelset_size _glp_mpl_arelset_size
+int arelset_size(MPL *mpl, double t0, double tf, double dt);
+/* compute size of "arithmetic" elemental set */
+
+#define arelset_member _glp_mpl_arelset_member
+double arelset_member(MPL *mpl, double t0, double tf, double dt, int j);
+/* compute member of "arithmetic" elemental set */
+
+#define create_arelset _glp_mpl_create_arelset
+ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt);
+/* create "arithmetic" elemental set */
+
+#define set_union _glp_mpl_set_union
+ELEMSET *set_union
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* union of two elemental sets */
+
+#define set_diff _glp_mpl_set_diff
+ELEMSET *set_diff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* difference between two elemental sets */
+
+#define set_symdiff _glp_mpl_set_symdiff
+ELEMSET *set_symdiff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* symmetric difference between two elemental sets */
+
+#define set_inter _glp_mpl_set_inter
+ELEMSET *set_inter
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* intersection of two elemental sets */
+
+#define set_cross _glp_mpl_set_cross
+ELEMSET *set_cross
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+);
+/* cross (Cartesian) product of two elemental sets */
+
+/**********************************************************************/
+/* * *                    ELEMENTAL VARIABLES                     * * */
+/**********************************************************************/
+
+struct ELEMVAR
+{     /* elemental variable; formally it is a "value" assigned to
+         members of model variables (like numbers and symbols, which
+         are values assigned to members of model parameters) */
+      int j;
+      /* LP column number assigned to this elemental variable */
+      VARIABLE *var;
+      /* model variable, which contains this elemental variable */
+      MEMBER *memb;
+      /* array member, which is assigned this elemental variable */
+      double lbnd;
+      /* lower bound */
+      double ubnd;
+      /* upper bound */
+      double temp;
+      /* working quantity used in operations on linear forms; normally
+         it contains floating-point zero */
+#if 1 /* 15/V-2010 */
+      int stat;
+      double prim, dual;
+      /* solution components provided by the solver */
+#endif
+};
+
+/**********************************************************************/
+/* * *                        LINEAR FORMS                        * * */
+/**********************************************************************/
+
+struct FORMULA
+{     /* term of linear form c * x, where c is a coefficient, x is an
+         elemental variable; the linear form itself is the sum of terms
+         and is associated with its first term; (note that the linear
+         form may be empty that means the sum is equal to zero) */
+      double coef;
+      /* coefficient at elemental variable or constant term */
+      ELEMVAR *var;
+      /* reference to elemental variable; NULL means constant term */
+      FORMULA *next;
+      /* the next term of linear form */
+};
+
+#define constant_term _glp_mpl_constant_term
+FORMULA *constant_term(MPL *mpl, double coef);
+/* create constant term */
+
+#define single_variable _glp_mpl_single_variable
+FORMULA *single_variable
+(     MPL *mpl,
+      ELEMVAR *var            /* referenced */
+);
+/* create single variable */
+
+#define copy_formula _glp_mpl_copy_formula
+FORMULA *copy_formula
+(     MPL *mpl,
+      FORMULA *form           /* not changed */
+);
+/* make copy of linear form */
+
+#define delete_formula _glp_mpl_delete_formula
+void delete_formula
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+);
+/* delete linear form */
+
+#define linear_comb _glp_mpl_linear_comb
+FORMULA *linear_comb
+(     MPL *mpl,
+      double a, FORMULA *fx,  /* destroyed */
+      double b, FORMULA *fy   /* destroyed */
+);
+/* linear combination of two linear forms */
+
+#define remove_constant _glp_mpl_remove_constant
+FORMULA *remove_constant
+(     MPL *mpl,
+      FORMULA *form,          /* destroyed */
+      double *coef            /* modified */
+);
+/* remove constant term from linear form */
+
+#define reduce_terms _glp_mpl_reduce_terms
+FORMULA *reduce_terms
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+);
+/* reduce identical terms in linear form */
+
+/**********************************************************************/
+/* * *                   ELEMENTAL CONSTRAINTS                    * * */
+/**********************************************************************/
+
+struct ELEMCON
+{     /* elemental constraint; formally it is a "value" assigned to
+         members of model constraints (like numbers or symbols, which
+         are values assigned to members of model parameters) */
+      int i;
+      /* LP row number assigned to this elemental constraint */
+      CONSTRAINT *con;
+      /* model constraint, which contains this elemental constraint */
+      MEMBER *memb;
+      /* array member, which is assigned this elemental constraint */
+      FORMULA *form;
+      /* linear form */
+      double lbnd;
+      /* lower bound */
+      double ubnd;
+      /* upper bound */
+#if 1 /* 15/V-2010 */
+      int stat;
+      double prim, dual;
+      /* solution components provided by the solver */
+#endif
+};
+
+/**********************************************************************/
+/* * *                       GENERIC VALUES                       * * */
+/**********************************************************************/
+
+union VALUE
+{     /* generic value, which can be assigned to object member or be a
+         result of evaluation of expression */
+      /* indicator that specifies the particular type of generic value
+         is stored in the corresponding array or pseudo-code descriptor
+         and can be one of the following:
+         A_NONE     - no value
+         A_NUMERIC  - floating-point number
+         A_SYMBOLIC - symbol
+         A_LOGICAL  - logical value
+         A_TUPLE    - n-tuple
+         A_ELEMSET  - elemental set
+         A_ELEMVAR  - elemental variable
+         A_FORMULA  - linear form
+         A_ELEMCON  - elemental constraint */
+      void *none;    /* null */
+      double num;    /* value */
+      SYMBOL *sym;   /* value */
+      int bit;       /* value */
+      TUPLE *tuple;  /* value */
+      ELEMSET *set;  /* value */
+      ELEMVAR *var;  /* reference */
+      FORMULA *form; /* value */
+      ELEMCON *con;  /* reference */
+};
+
+#define delete_value _glp_mpl_delete_value
+void delete_value
+(     MPL *mpl,
+      int type,
+      VALUE *value            /* content destroyed */
+);
+/* delete generic value */
+
+/**********************************************************************/
+/* * *                SYMBOLICALLY INDEXED ARRAYS                 * * */
+/**********************************************************************/
+
+struct ARRAY
+{     /* multi-dimensional array, a set of members indexed over simple
+         or compound sets of symbols; arrays are used to represent the
+         contents of model objects (i.e. sets, parameters, variables,
+         constraints, and objectives); arrays also are used as "values"
+         that are assigned to members of set objects, in which case the
+         array itself represents an elemental set */
+      int type;
+      /* type of generic values assigned to the array members:
+         A_NONE     - none (members have no assigned values)
+         A_NUMERIC  - floating-point numbers
+         A_SYMBOLIC - symbols
+         A_ELEMSET  - elemental sets
+         A_ELEMVAR  - elemental variables
+         A_ELEMCON  - elemental constraints */
+      int dim;
+      /* dimension of the array that determines number of components in
+         n-tuples for all members of the array, dim >= 0; dim = 0 means
+         the array is 0-dimensional */
+      int size;
+      /* size of the array, i.e. number of its members */
+      MEMBER *head;
+      /* the first array member; NULL means the array is empty */
+      MEMBER *tail;
+      /* the last array member; NULL means the array is empty */
+      AVL *tree;
+      /* the search tree intended to find array members for logarithmic
+         time; NULL means the search tree doesn't exist */
+      ARRAY *prev;
+      /* the previous array in the translator database */
+      ARRAY *next;
+      /* the next array in the translator database */
+};
+
+struct MEMBER
+{     /* array member */
+      TUPLE *tuple;
+      /* n-tuple, which identifies the member; number of its components
+         is the same for all members within the array and determined by
+         the array dimension; duplicate members are not allowed */
+      MEMBER *next;
+      /* the next array member */
+      VALUE value;
+      /* generic value assigned to the member */
+};
+
+#define create_array _glp_mpl_create_array
+ARRAY *create_array(MPL *mpl, int type, int dim);
+/* create array */
+
+#define find_member _glp_mpl_find_member
+MEMBER *find_member
+(     MPL *mpl,
+      ARRAY *array,           /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* find array member with given n-tuple */
+
+#define add_member _glp_mpl_add_member
+MEMBER *add_member
+(     MPL *mpl,
+      ARRAY *array,           /* modified */
+      TUPLE *tuple            /* destroyed */
+);
+/* add new member to array */
+
+#define delete_array _glp_mpl_delete_array
+void delete_array
+(     MPL *mpl,
+      ARRAY *array            /* destroyed */
+);
+/* delete array */
+
+/**********************************************************************/
+/* * *                 DOMAINS AND DUMMY INDICES                  * * */
+/**********************************************************************/
+
+struct DOMAIN
+{     /* domain (a simple or compound set); syntactically domain looks
+         like '{ i in I, (j,k) in S, t in T : <predicate> }'; domains
+         are used to define sets, over which model objects are indexed,
+         and also as constituents of iterated operators */
+      DOMAIN_BLOCK *list;
+      /* linked list of domain blocks (in the example above such blocks
+         are 'i in I', '(j,k) in S', and 't in T'); this list cannot be
+         empty */
+      CODE *code;
+      /* pseudo-code for computing the logical predicate, which follows
+         the colon; NULL means no predicate is specified */
+};
+
+struct DOMAIN_BLOCK
+{     /* domain block; syntactically domain blocks look like 'i in I',
+         '(j,k) in S', and 't in T' in the example above (in the sequel
+         sets like I, S, and T are called basic sets) */
+      DOMAIN_SLOT *list;
+      /* linked list of domain slots (i.e. indexing positions); number
+         of slots in this list is the same as dimension of n-tuples in
+         the basic set; this list cannot be empty */
+      CODE *code;
+      /* pseudo-code for computing basic set; cannot be NULL */
+      TUPLE *backup;
+      /* if this n-tuple is not empty, current values of dummy indices
+         in the domain block are the same as components of this n-tuple
+         (note that this n-tuple may have larger dimension than number
+         of dummy indices in this block, in which case extra components
+         are ignored); this n-tuple is used to restore former values of
+         dummy indices, if they were changed due to recursive calls to
+         the domain block */
+      DOMAIN_BLOCK *next;
+      /* the next block in the same domain */
+};
+
+struct DOMAIN_SLOT
+{     /* domain slot; it specifies an individual indexing position and
+         defines the corresponding dummy index */
+      char *name;
+      /* symbolic name of the dummy index; null pointer means the dummy
+         index is not explicitly specified */
+      CODE *code;
+      /* pseudo-code for computing symbolic value, at which the dummy
+         index is bound; NULL means the dummy index is free within the
+         domain scope */
+      SYMBOL *value;
+      /* current value assigned to the dummy index; NULL means no value
+         is assigned at the moment */
+      CODE *list;
+      /* linked list of pseudo-codes with operation O_INDEX referring
+         to this slot; this linked list is used to invalidate resultant
+         values of the operation, which depend on this dummy index */
+      DOMAIN_SLOT *next;
+      /* the next slot in the same domain block */
+};
+
+#define assign_dummy_index _glp_mpl_assign_dummy_index
+void assign_dummy_index
+(     MPL *mpl,
+      DOMAIN_SLOT *slot,      /* modified */
+      SYMBOL *value           /* not changed */
+);
+/* assign new value to dummy index */
+
+#define update_dummy_indices _glp_mpl_update_dummy_indices
+void update_dummy_indices
+(     MPL *mpl,
+      DOMAIN_BLOCK *block     /* not changed */
+);
+/* update current values of dummy indices */
+
+#define enter_domain_block _glp_mpl_enter_domain_block
+int enter_domain_block
+(     MPL *mpl,
+      DOMAIN_BLOCK *block,    /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+);
+/* enter domain block */
+
+#define eval_within_domain _glp_mpl_eval_within_domain
+int eval_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+);
+/* perform evaluation within domain scope */
+
+#define loop_within_domain _glp_mpl_loop_within_domain
+void loop_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      void *info, int (*func)(MPL *mpl, void *info)
+);
+/* perform iterations within domain scope */
+
+#define out_of_domain _glp_mpl_out_of_domain
+void out_of_domain
+(     MPL *mpl,
+      char *name,             /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* raise domain exception */
+
+#define get_domain_tuple _glp_mpl_get_domain_tuple
+TUPLE *get_domain_tuple
+(     MPL *mpl,
+      DOMAIN *domain          /* not changed */
+);
+/* obtain current n-tuple from domain */
+
+#define clean_domain _glp_mpl_clean_domain
+void clean_domain(MPL *mpl, DOMAIN *domain);
+/* clean domain */
+
+/**********************************************************************/
+/* * *                         MODEL SETS                         * * */
+/**********************************************************************/
+
+struct SET
+{     /* model set */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) set, dim > 0 means set of sets */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional set */
+      int dimen;
+      /* dimension of n-tuples, which members of this set consist of
+         (note that the model set itself is an array of elemental sets,
+         which are its members; so, don't confuse this dimension with
+         dimension of the model set); always non-zero */
+      WITHIN *within;
+      /* list of supersets, which restrict each member of the set to be
+         in every superset from this list; this list can be empty */
+      CODE *assign;
+      /* pseudo-code for computing assigned value; can be NULL */
+      CODE *option;
+      /* pseudo-code for computing default value; can be NULL */
+      GADGET *gadget;
+      /* plain set used to initialize the array of sets; can be NULL */
+      int data;
+      /* data status flag:
+         0 - no data are provided in the data section
+         1 - data are provided, but not checked yet
+         2 - data are provided and have been checked */
+      ARRAY *array;
+      /* array of members, which are assigned elemental sets */
+};
+
+struct WITHIN
+{     /* restricting superset list entry */
+      CODE *code;
+      /* pseudo-code for computing the superset; cannot be NULL */
+      WITHIN *next;
+      /* the next entry for the same set or parameter */
+};
+
+struct GADGET
+{     /* plain set used to initialize the array of sets with data */
+      SET *set;
+      /* pointer to plain set; cannot be NULL */
+      int ind[20]; /* ind[dim+dimen]; */
+      /* permutation of integers 1, 2, ..., dim+dimen */
+};
+
+#define check_elem_set _glp_mpl_check_elem_set
+void check_elem_set
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple,           /* not changed */
+      ELEMSET *refer          /* not changed */
+);
+/* check elemental set assigned to set member */
+
+#define take_member_set _glp_mpl_take_member_set
+ELEMSET *take_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain elemental set assigned to set member */
+
+#define eval_member_set _glp_mpl_eval_member_set
+ELEMSET *eval_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate elemental set assigned to set member */
+
+#define eval_whole_set _glp_mpl_eval_whole_set
+void eval_whole_set(MPL *mpl, SET *set);
+/* evaluate model set over entire domain */
+
+#define clean_set _glp_mpl_clean_set
+void clean_set(MPL *mpl, SET *set);
+/* clean model set */
+
+/**********************************************************************/
+/* * *                      MODEL PARAMETERS                      * * */
+/**********************************************************************/
+
+struct PARAMETER
+{     /* model parameter */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) parameter */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional parameter */
+      int type;
+      /* parameter type:
+         A_NUMERIC  - numeric
+         A_INTEGER  - integer
+         A_BINARY   - binary
+         A_SYMBOLIC - symbolic */
+      CONDITION *cond;
+      /* list of conditions, which restrict each parameter member to
+         satisfy to every condition from this list; this list is used
+         only for numeric parameters and can be empty */
+      WITHIN *in;
+      /* list of supersets, which restrict each parameter member to be
+         in every superset from this list; this list is used only for
+         symbolic parameters and can be empty */
+      CODE *assign;
+      /* pseudo-code for computing assigned value; can be NULL */
+      CODE *option;
+      /* pseudo-code for computing default value; can be NULL */
+      int data;
+      /* data status flag:
+         0 - no data are provided in the data section
+         1 - data are provided, but not checked yet
+         2 - data are provided and have been checked */
+      SYMBOL *defval;
+      /* default value provided in the data section; can be NULL */
+      ARRAY *array;
+      /* array of members, which are assigned numbers or symbols */
+};
+
+struct CONDITION
+{     /* restricting condition list entry */
+      int rho;
+      /* flag that specifies the form of the condition:
+         O_LT - less than
+         O_LE - less than or equal to
+         O_EQ - equal to
+         O_GE - greater than or equal to
+         O_GT - greater than
+         O_NE - not equal to */
+      CODE *code;
+      /* pseudo-code for computing the reference value */
+      CONDITION *next;
+      /* the next entry for the same parameter */
+};
+
+#define check_value_num _glp_mpl_check_value_num
+void check_value_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      double value
+);
+/* check numeric value assigned to parameter member */
+
+#define take_member_num _glp_mpl_take_member_num
+double take_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain numeric value assigned to parameter member */
+
+#define eval_member_num _glp_mpl_eval_member_num
+double eval_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate numeric value assigned to parameter member */
+
+#define check_value_sym _glp_mpl_check_value_sym
+void check_value_sym
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      SYMBOL *value           /* not changed */
+);
+/* check symbolic value assigned to parameter member */
+
+#define take_member_sym _glp_mpl_take_member_sym
+SYMBOL *take_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain symbolic value assigned to parameter member */
+
+#define eval_member_sym _glp_mpl_eval_member_sym
+SYMBOL *eval_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate symbolic value assigned to parameter member */
+
+#define eval_whole_par _glp_mpl_eval_whole_par
+void eval_whole_par(MPL *mpl, PARAMETER *par);
+/* evaluate model parameter over entire domain */
+
+#define clean_parameter _glp_mpl_clean_parameter
+void clean_parameter(MPL *mpl, PARAMETER *par);
+/* clean model parameter */
+
+/**********************************************************************/
+/* * *                      MODEL VARIABLES                       * * */
+/**********************************************************************/
+
+struct VARIABLE
+{     /* model variable */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) variable */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional variable */
+      int type;
+      /* variable type:
+         A_NUMERIC - continuous
+         A_INTEGER - integer
+         A_BINARY  - binary */
+      CODE *lbnd;
+      /* pseudo-code for computing lower bound; NULL means lower bound
+         is not specified */
+      CODE *ubnd;
+      /* pseudo-code for computing upper bound; NULL means upper bound
+         is not specified */
+      /* if both the pointers lbnd and ubnd refer to the same code, the
+         variable is fixed at the corresponding value */
+      ARRAY *array;
+      /* array of members, which are assigned elemental variables */
+};
+
+#define take_member_var _glp_mpl_take_member_var
+ELEMVAR *take_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain reference to elemental variable */
+
+#define eval_member_var _glp_mpl_eval_member_var
+ELEMVAR *eval_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate reference to elemental variable */
+
+#define eval_whole_var _glp_mpl_eval_whole_var
+void eval_whole_var(MPL *mpl, VARIABLE *var);
+/* evaluate model variable over entire domain */
+
+#define clean_variable _glp_mpl_clean_variable
+void clean_variable(MPL *mpl, VARIABLE *var);
+/* clean model variable */
+
+/**********************************************************************/
+/* * *              MODEL CONSTRAINTS AND OBJECTIVES              * * */
+/**********************************************************************/
+
+struct CONSTRAINT
+{     /* model constraint or objective */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int dim; /* aka arity */
+      /* dimension (number of subscripts); dim = 0 means 0-dimensional
+         (unsubscripted) constraint */
+      DOMAIN *domain;
+      /* subscript domain; NULL for 0-dimensional constraint */
+      int type;
+      /* constraint type:
+         A_CONSTRAINT - constraint
+         A_MINIMIZE   - objective (minimization)
+         A_MAXIMIZE   - objective (maximization) */
+      CODE *code;
+      /* pseudo-code for computing main linear form; cannot be NULL */
+      CODE *lbnd;
+      /* pseudo-code for computing lower bound; NULL means lower bound
+         is not specified */
+      CODE *ubnd;
+      /* pseudo-code for computing upper bound; NULL means upper bound
+         is not specified */
+      /* if both the pointers lbnd and ubnd refer to the same code, the
+         constraint has the form of equation */
+      ARRAY *array;
+      /* array of members, which are assigned elemental constraints */
+};
+
+#define take_member_con _glp_mpl_take_member_con
+ELEMCON *take_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* obtain reference to elemental constraint */
+
+#define eval_member_con _glp_mpl_eval_member_con
+ELEMCON *eval_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+);
+/* evaluate reference to elemental constraint */
+
+#define eval_whole_con _glp_mpl_eval_whole_con
+void eval_whole_con(MPL *mpl, CONSTRAINT *con);
+/* evaluate model constraint over entire domain */
+
+#define clean_constraint _glp_mpl_clean_constraint
+void clean_constraint(MPL *mpl, CONSTRAINT *con);
+/* clean model constraint */
+
+/**********************************************************************/
+/* * *                        DATA TABLES                         * * */
+/**********************************************************************/
+
+struct TABLE
+{     /* data table */
+      char *name;
+      /* symbolic name; cannot be NULL */
+      char *alias;
+      /* alias; NULL means alias is not specified */
+      int type;
+      /* table type:
+         A_INPUT  - input table
+         A_OUTPUT - output table */
+      TABARG *arg;
+      /* argument list; cannot be empty */
+      union
+      {  struct
+         {  SET *set;
+            /* input set; NULL means the set is not specified */
+            TABFLD *fld;
+            /* field list; cannot be empty */
+            TABIN *list;
+            /* input list; can be empty */
+         } in;
+         struct
+         {  DOMAIN *domain;
+            /* subscript domain; cannot be NULL */
+            TABOUT *list;
+            /* output list; cannot be empty */
+         } out;
+      } u;
+};
+
+struct TABARG
+{     /* table argument list entry */
+      CODE *code;
+      /* pseudo-code for computing the argument */
+      TABARG *next;
+      /* next entry for the same table */
+};
+
+struct TABFLD
+{     /* table field list entry */
+      char *name;
+      /* field name; cannot be NULL */
+      TABFLD *next;
+      /* next entry for the same table */
+};
+
+struct TABIN
+{     /* table input list entry */
+      PARAMETER *par;
+      /* parameter to be read; cannot be NULL */
+      char *name;
+      /* column name; cannot be NULL */
+      TABIN *next;
+      /* next entry for the same table */
+};
+
+struct TABOUT
+{     /* table output list entry */
+      CODE *code;
+      /* pseudo-code for computing the value to be written */
+      char *name;
+      /* column name; cannot be NULL */
+      TABOUT *next;
+      /* next entry for the same table */
+};
+
+struct TABDCA
+{     /* table driver communication area */
+      int id;
+      /* driver identifier (set by mpl_tab_drv_open) */
+      void *link;
+      /* driver link pointer (set by mpl_tab_drv_open) */
+      int na;
+      /* number of arguments */
+      char **arg; /* char *arg[1+ns]; */
+      /* arg[k], 1 <= k <= ns, is pointer to k-th argument */
+      int nf;
+      /* number of fields */
+      char **name; /* char *name[1+nc]; */
+      /* name[k], 1 <= k <= nc, is name of k-th field */
+      int *type; /* int type[1+nc]; */
+      /* type[k], 1 <= k <= nc, is type of k-th field:
+         '?' - value not assigned
+         'N' - number
+         'S' - character string */
+      double *num; /* double num[1+nc]; */
+      /* num[k], 1 <= k <= nc, is numeric value of k-th field */
+      char **str;
+      /* str[k], 1 <= k <= nc, is string value of k-th field */
+};
+
+#define mpl_tab_num_args _glp_mpl_tab_num_args
+int mpl_tab_num_args(TABDCA *dca);
+
+#define mpl_tab_get_arg _glp_mpl_tab_get_arg
+const char *mpl_tab_get_arg(TABDCA *dca, int k);
+
+#define mpl_tab_num_flds _glp_mpl_tab_num_flds
+int mpl_tab_num_flds(TABDCA *dca);
+
+#define mpl_tab_get_name _glp_mpl_tab_get_name
+const char *mpl_tab_get_name(TABDCA *dca, int k);
+
+#define mpl_tab_get_type _glp_mpl_tab_get_type
+int mpl_tab_get_type(TABDCA *dca, int k);
+
+#define mpl_tab_get_num _glp_mpl_tab_get_num
+double mpl_tab_get_num(TABDCA *dca, int k);
+
+#define mpl_tab_get_str _glp_mpl_tab_get_str
+const char *mpl_tab_get_str(TABDCA *dca, int k);
+
+#define mpl_tab_set_num _glp_mpl_tab_set_num
+void mpl_tab_set_num(TABDCA *dca, int k, double num);
+
+#define mpl_tab_set_str _glp_mpl_tab_set_str
+void mpl_tab_set_str(TABDCA *dca, int k, const char *str);
+
+#define mpl_tab_drv_open _glp_mpl_tab_drv_open
+void mpl_tab_drv_open(MPL *mpl, int mode);
+
+#define mpl_tab_drv_read _glp_mpl_tab_drv_read
+int mpl_tab_drv_read(MPL *mpl);
+
+#define mpl_tab_drv_write _glp_mpl_tab_drv_write
+void mpl_tab_drv_write(MPL *mpl);
+
+#define mpl_tab_drv_close _glp_mpl_tab_drv_close
+void mpl_tab_drv_close(MPL *mpl);
+
+/**********************************************************************/
+/* * *                        PSEUDO-CODE                         * * */
+/**********************************************************************/
+
+union OPERANDS
+{     /* operands that participate in pseudo-code operation (choice of
+         particular operands depends on the operation code) */
+      /*--------------------------------------------------------------*/
+      double num;             /* O_NUMBER */
+      /* floaing-point number to be taken */
+      /*--------------------------------------------------------------*/
+      char *str;              /* O_STRING */
+      /* character string to be taken */
+      /*--------------------------------------------------------------*/
+      struct                  /* O_INDEX */
+      {  DOMAIN_SLOT *slot;
+         /* domain slot, which contains dummy index to be taken */
+         CODE *next;
+         /* the next pseudo-code with op = O_INDEX, which refers to the
+            same slot as this one; pointer to the beginning of this list
+            is stored in the corresponding domain slot */
+      } index;
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMNUM, O_MEMSYM */
+      {  PARAMETER *par;
+         /* model parameter, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripts; NULL for 0-dimensional parameter */
+      } par;
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMSET */
+      {  SET *set;
+         /* model set, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripts; NULL for 0-dimensional set */
+      } set;
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMVAR */
+      {  VARIABLE *var;
+         /* model variable, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripts; NULL for 0-dimensional variable */
+#if 1 /* 15/V-2010 */
+         int suff;
+         /* suffix specified: */
+#define DOT_NONE        0x00  /* none     (means variable itself) */
+#define DOT_LB          0x01  /* .lb      (lower bound) */
+#define DOT_UB          0x02  /* .ub      (upper bound) */
+#define DOT_STATUS      0x03  /* .status  (status) */
+#define DOT_VAL         0x04  /* .val     (primal value) */
+#define DOT_DUAL        0x05  /* .dual    (dual value) */
+#endif
+      } var;
+#if 1 /* 15/V-2010 */
+      /*--------------------------------------------------------------*/
+      struct                  /* O_MEMCON */
+      {  CONSTRAINT *con;
+         /* model constraint, which contains member to be taken */
+         ARG_LIST *list;
+         /* list of subscripys; NULL for 0-dimensional constraint */
+         int suff;
+         /* suffix specified (see O_MEMVAR above) */
+      } con;
+#endif
+      /*--------------------------------------------------------------*/
+      ARG_LIST *list;         /* O_TUPLE, O_MAKE, n-ary operations */
+      /* list of operands */
+      /*--------------------------------------------------------------*/
+      DOMAIN_BLOCK *slice;    /* O_SLICE */
+      /* domain block, which specifies slice (i.e. n-tuple that contains
+         free dummy indices); this operation is never evaluated */
+      /*--------------------------------------------------------------*/
+      struct                  /* unary, binary, ternary operations */
+      {  CODE *x;
+         /* pseudo-code for computing first operand */
+         CODE *y;
+         /* pseudo-code for computing second operand */
+         CODE *z;
+         /* pseudo-code for computing third operand */
+      } arg;
+      /*--------------------------------------------------------------*/
+      struct                  /* iterated operations */
+      {  DOMAIN *domain;
+         /* domain, over which the operation is performed */
+         CODE *x;
+         /* pseudo-code for computing "integrand" */
+      } loop;
+      /*--------------------------------------------------------------*/
+};
+
+struct ARG_LIST
+{     /* operands list entry */
+      CODE *x;
+      /* pseudo-code for computing operand */
+      ARG_LIST *next;
+      /* the next operand of the same operation */
+};
+
+struct CODE
+{     /* pseudo-code (internal form of expressions) */
+      int op;
+      /* operation code: */
+#define O_NUMBER        301   /* take floating-point number */
+#define O_STRING        302   /* take character string */
+#define O_INDEX         303   /* take dummy index */
+#define O_MEMNUM        304   /* take member of numeric parameter */
+#define O_MEMSYM        305   /* take member of symbolic parameter */
+#define O_MEMSET        306   /* take member of set */
+#define O_MEMVAR        307   /* take member of variable */
+#define O_MEMCON        308   /* take member of constraint */
+#define O_TUPLE         309   /* make n-tuple */
+#define O_MAKE          310   /* make elemental set of n-tuples */
+#define O_SLICE         311   /* define domain block (dummy op) */
+                              /* 0-ary operations --------------------*/
+#define O_IRAND224      312   /* pseudo-random in [0, 2^24-1] */
+#define O_UNIFORM01     313   /* pseudo-random in [0, 1) */
+#define O_NORMAL01      314   /* gaussian random, mu = 0, sigma = 1 */
+#define O_GMTIME        315   /* current calendar time (UTC) */
+                              /* unary operations --------------------*/
+#define O_CVTNUM        316   /* conversion to numeric */
+#define O_CVTSYM        317   /* conversion to symbolic */
+#define O_CVTLOG        318   /* conversion to logical */
+#define O_CVTTUP        319   /* conversion to 1-tuple */
+#define O_CVTLFM        320   /* conversion to linear form */
+#define O_PLUS          321   /* unary plus */
+#define O_MINUS         322   /* unary minus */
+#define O_NOT           323   /* negation (logical "not") */
+#define O_ABS           324   /* absolute value */
+#define O_CEIL          325   /* round upward ("ceiling of x") */
+#define O_FLOOR         326   /* round downward ("floor of x") */
+#define O_EXP           327   /* base-e exponential */
+#define O_LOG           328   /* natural logarithm */
+#define O_LOG10         329   /* common (decimal) logarithm */
+#define O_SQRT          330   /* square root */
+#define O_SIN           331   /* trigonometric sine */
+#define O_COS           332   /* trigonometric cosine */
+#define O_ATAN          333   /* trigonometric arctangent */
+#define O_ROUND         334   /* round to nearest integer */
+#define O_TRUNC         335   /* truncate to nearest integer */
+#define O_CARD          336   /* cardinality of set */
+#define O_LENGTH        337   /* length of symbolic value */
+                              /* binary operations -------------------*/
+#define O_ADD           338   /* addition */
+#define O_SUB           339   /* subtraction */
+#define O_LESS          340   /* non-negative subtraction */
+#define O_MUL           341   /* multiplication */
+#define O_DIV           342   /* division */
+#define O_IDIV          343   /* quotient of exact division */
+#define O_MOD           344   /* remainder of exact division */
+#define O_POWER         345   /* exponentiation (raise to power) */
+#define O_ATAN2         346   /* trigonometric arctangent */
+#define O_ROUND2        347   /* round to n fractional digits */
+#define O_TRUNC2        348   /* truncate to n fractional digits */
+#define O_UNIFORM       349   /* pseudo-random in [a, b) */
+#define O_NORMAL        350   /* gaussian random, given mu and sigma */
+#define O_CONCAT        351   /* concatenation */
+#define O_LT            352   /* comparison on 'less than' */
+#define O_LE            353   /* comparison on 'not greater than' */
+#define O_EQ            354   /* comparison on 'equal to' */
+#define O_GE            355   /* comparison on 'not less than' */
+#define O_GT            356   /* comparison on 'greater than' */
+#define O_NE            357   /* comparison on 'not equal to' */
+#define O_AND           358   /* conjunction (logical "and") */
+#define O_OR            359   /* disjunction (logical "or") */
+#define O_UNION         360   /* union */
+#define O_DIFF          361   /* difference */
+#define O_SYMDIFF       362   /* symmetric difference */
+#define O_INTER         363   /* intersection */
+#define O_CROSS         364   /* cross (Cartesian) product */
+#define O_IN            365   /* test on 'x in Y' */
+#define O_NOTIN         366   /* test on 'x not in Y' */
+#define O_WITHIN        367   /* test on 'X within Y' */
+#define O_NOTWITHIN     368   /* test on 'X not within Y' */
+#define O_SUBSTR        369   /* substring */
+#define O_STR2TIME      370   /* convert string to time */
+#define O_TIME2STR      371   /* convert time to string */
+                              /* ternary operations ------------------*/
+#define O_DOTS          372   /* build "arithmetic" set */
+#define O_FORK          373   /* if-then-else */
+#define O_SUBSTR3       374   /* substring */
+                              /* n-ary operations --------------------*/
+#define O_MIN           375   /* minimal value (n-ary) */
+#define O_MAX           376   /* maximal value (n-ary) */
+                              /* iterated operations -----------------*/
+#define O_SUM           377   /* summation */
+#define O_PROD          378   /* multiplication */
+#define O_MINIMUM       379   /* minimum */
+#define O_MAXIMUM       380   /* maximum */
+#define O_FORALL        381   /* conjunction (A-quantification) */
+#define O_EXISTS        382   /* disjunction (E-quantification) */
+#define O_SETOF         383   /* compute elemental set */
+#define O_BUILD         384   /* build elemental set */
+      OPERANDS arg;
+      /* operands that participate in the operation */
+      int type;
+      /* type of the resultant value:
+         A_NUMERIC  - numeric
+         A_SYMBOLIC - symbolic
+         A_LOGICAL  - logical
+         A_TUPLE    - n-tuple
+         A_ELEMSET  - elemental set
+         A_FORMULA  - linear form */
+      int dim;
+      /* dimension of the resultant value; for A_TUPLE and A_ELEMSET it
+         is the dimension of the corresponding n-tuple(s) and cannot be
+         zero; for other resultant types it is always zero */
+      CODE *up;
+      /* parent pseudo-code, which refers to this pseudo-code as to its
+         operand; NULL means this pseudo-code has no parent and defines
+         an expression, which is not contained in another expression */
+      int vflag;
+      /* volatile flag; being set this flag means that this operation
+         has a side effect; for primary expressions this flag is set
+         directly by corresponding parsing routines (for example, if
+         primary expression is a reference to a function that generates
+         pseudo-random numbers); in other cases this flag is inherited
+         from operands */
+      int valid;
+      /* if this flag is set, the resultant value, which is a temporary
+         result of evaluating this operation on particular values of
+         operands, is valid; if this flag is clear, the resultant value
+         doesn't exist and therefore not valid; having been evaluated
+         the resultant value is stored here and not destroyed until the
+         dummy indices, which this value depends on, have been changed
+         (and if it doesn't depend on dummy indices at all, it is never
+         destroyed); thus, if the resultant value is valid, evaluating
+         routine can immediately take its copy not computing the result
+         from scratch; this mechanism is similar to moving invariants
+         out of loops and allows improving efficiency at the expense of
+         some extra memory needed to keep temporary results */
+      /* however, if the volatile flag (see above) is set, even if the
+         resultant value is valid, evaluating routine computes it as if
+         it were not valid, i.e. caching is not used in this case */
+      VALUE value;
+      /* resultant value in generic format */
+};
+
+#define eval_numeric _glp_mpl_eval_numeric
+double eval_numeric(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine numeric value */
+
+#define eval_symbolic _glp_mpl_eval_symbolic
+SYMBOL *eval_symbolic(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine symbolic value */
+
+#define eval_logical _glp_mpl_eval_logical
+int eval_logical(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to determine logical value */
+
+#define eval_tuple _glp_mpl_eval_tuple
+TUPLE *eval_tuple(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct n-tuple */
+
+#define eval_elemset _glp_mpl_eval_elemset
+ELEMSET *eval_elemset(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct elemental set */
+
+#define is_member _glp_mpl_is_member
+int is_member(MPL *mpl, CODE *code, TUPLE *tuple);
+/* check if n-tuple is in set specified by pseudo-code */
+
+#define eval_formula _glp_mpl_eval_formula
+FORMULA *eval_formula(MPL *mpl, CODE *code);
+/* evaluate pseudo-code to construct linear form */
+
+#define clean_code _glp_mpl_clean_code
+void clean_code(MPL *mpl, CODE *code);
+/* clean pseudo-code */
+
+/**********************************************************************/
+/* * *                      MODEL STATEMENTS                      * * */
+/**********************************************************************/
+
+struct CHECK
+{     /* check statement */
+      DOMAIN *domain;
+      /* subscript domain; NULL means domain is not used */
+      CODE *code;
+      /* code for computing the predicate to be checked */
+};
+
+struct DISPLAY
+{     /* display statement */
+      DOMAIN *domain;
+      /* subscript domain; NULL means domain is not used */
+      DISPLAY1 *list;
+      /* display list; cannot be empty */
+};
+
+struct DISPLAY1
+{     /* display list entry */
+      int type;
+      /* item type:
+         A_INDEX      - dummy index
+         A_SET        - model set
+         A_PARAMETER  - model parameter
+         A_VARIABLE   - model variable
+         A_CONSTRAINT - model constraint/objective
+         A_EXPRESSION - expression */
+      union
+      {  DOMAIN_SLOT *slot;
+         SET *set;
+         PARAMETER *par;
+         VARIABLE *var;
+         CONSTRAINT *con;
+         CODE *code;
+      } u;
+      /* item to be displayed */
+#if 0 /* 15/V-2010 */
+      ARG_LIST *list;
+      /* optional subscript list (for constraint/objective only) */
+#endif
+      DISPLAY1 *next;
+      /* the next entry for the same statement */
+};
+
+struct PRINTF
+{     /* printf statement */
+      DOMAIN *domain;
+      /* subscript domain; NULL means domain is not used */
+      CODE *fmt;
+      /* pseudo-code for computing format string */
+      PRINTF1 *list;
+      /* printf list; can be empty */
+      CODE *fname;
+      /* pseudo-code for computing filename to redirect the output;
+         NULL means the output goes to stdout */
+      int app;
+      /* if this flag is set, the output is appended */
+};
+
+struct PRINTF1
+{     /* printf list entry */
+      CODE *code;
+      /* pseudo-code for computing value to be printed */
+      PRINTF1 *next;
+      /* the next entry for the same statement */
+};
+
+struct FOR
+{     /* for statement */
+      DOMAIN *domain;
+      /* subscript domain; cannot be NULL */
+      STATEMENT *list;
+      /* linked list of model statements within this for statement in
+         the original order */
+};
+
+struct STATEMENT
+{     /* model statement */
+      int line;
+      /* number of source text line, where statement begins */
+      int type;
+      /* statement type:
+         A_SET        - set statement
+         A_PARAMETER  - parameter statement
+         A_VARIABLE   - variable statement
+         A_CONSTRAINT - constraint/objective statement
+         A_TABLE      - table statement
+         A_SOLVE      - solve statement
+         A_CHECK      - check statement
+         A_DISPLAY    - display statement
+         A_PRINTF     - printf statement
+         A_FOR        - for statement */
+      union
+      {  SET *set;
+         PARAMETER *par;
+         VARIABLE *var;
+         CONSTRAINT *con;
+         TABLE *tab;
+         void *slv; /* currently not used (set to NULL) */
+         CHECK *chk;
+         DISPLAY *dpy;
+         PRINTF *prt;
+         FOR *fur;
+      } u;
+      /* specific part of statement */
+      STATEMENT *next;
+      /* the next statement; in this list statements follow in the same
+         order as they appear in the model section */
+};
+
+#define execute_table _glp_mpl_execute_table
+void execute_table(MPL *mpl, TABLE *tab);
+/* execute table statement */
+
+#define free_dca _glp_mpl_free_dca
+void free_dca(MPL *mpl);
+/* free table driver communucation area */
+
+#define clean_table _glp_mpl_clean_table
+void clean_table(MPL *mpl, TABLE *tab);
+/* clean table statement */
+
+#define execute_check _glp_mpl_execute_check
+void execute_check(MPL *mpl, CHECK *chk);
+/* execute check statement */
+
+#define clean_check _glp_mpl_clean_check
+void clean_check(MPL *mpl, CHECK *chk);
+/* clean check statement */
+
+#define execute_display _glp_mpl_execute_display
+void execute_display(MPL *mpl, DISPLAY *dpy);
+/* execute display statement */
+
+#define clean_display _glp_mpl_clean_display
+void clean_display(MPL *mpl, DISPLAY *dpy);
+/* clean display statement */
+
+#define execute_printf _glp_mpl_execute_printf
+void execute_printf(MPL *mpl, PRINTF *prt);
+/* execute printf statement */
+
+#define clean_printf _glp_mpl_clean_printf
+void clean_printf(MPL *mpl, PRINTF *prt);
+/* clean printf statement */
+
+#define execute_for _glp_mpl_execute_for
+void execute_for(MPL *mpl, FOR *fur);
+/* execute for statement */
+
+#define clean_for _glp_mpl_clean_for
+void clean_for(MPL *mpl, FOR *fur);
+/* clean for statement */
+
+#define execute_statement _glp_mpl_execute_statement
+void execute_statement(MPL *mpl, STATEMENT *stmt);
+/* execute specified model statement */
+
+#define clean_statement _glp_mpl_clean_statement
+void clean_statement(MPL *mpl, STATEMENT *stmt);
+/* clean specified model statement */
+
+/**********************************************************************/
+/* * *              GENERATING AND POSTSOLVING MODEL              * * */
+/**********************************************************************/
+
+#define alloc_content _glp_mpl_alloc_content
+void alloc_content(MPL *mpl);
+/* allocate content arrays for all model objects */
+
+#define generate_model _glp_mpl_generate_model
+void generate_model(MPL *mpl);
+/* generate model */
+
+#define build_problem _glp_mpl_build_problem
+void build_problem(MPL *mpl);
+/* build problem instance */
+
+#define postsolve_model _glp_mpl_postsolve_model
+void postsolve_model(MPL *mpl);
+/* postsolve model */
+
+#define clean_model _glp_mpl_clean_model
+void clean_model(MPL *mpl);
+/* clean model content */
+
+/**********************************************************************/
+/* * *                        INPUT/OUTPUT                        * * */
+/**********************************************************************/
+
+#define open_input _glp_mpl_open_input
+void open_input(MPL *mpl, char *file);
+/* open input text file */
+
+#define read_char _glp_mpl_read_char
+int read_char(MPL *mpl);
+/* read next character from input text file */
+
+#define close_input _glp_mpl_close_input
+void close_input(MPL *mpl);
+/* close input text file */
+
+#define open_output _glp_mpl_open_output
+void open_output(MPL *mpl, char *file);
+/* open output text file */
+
+#define write_char _glp_mpl_write_char
+void write_char(MPL *mpl, int c);
+/* write next character to output text file */
+
+#define write_text _glp_mpl_write_text
+void write_text(MPL *mpl, char *fmt, ...);
+/* format and write text to output text file */
+
+#define flush_output _glp_mpl_flush_output
+void flush_output(MPL *mpl);
+/* finalize writing data to output text file */
+
+/**********************************************************************/
+/* * *                      SOLVER INTERFACE                      * * */
+/**********************************************************************/
+
+#define MPL_FR          401   /* free (unbounded) */
+#define MPL_LO          402   /* lower bound */
+#define MPL_UP          403   /* upper bound */
+#define MPL_DB          404   /* both lower and upper bounds */
+#define MPL_FX          405   /* fixed */
+
+#define MPL_ST          411   /* constraint */
+#define MPL_MIN         412   /* objective (minimization) */
+#define MPL_MAX         413   /* objective (maximization) */
+
+#define MPL_NUM         421   /* continuous */
+#define MPL_INT         422   /* integer */
+#define MPL_BIN         423   /* binary */
+
+#define error _glp_mpl_error
+void error(MPL *mpl, char *fmt, ...);
+/* print error message and terminate model processing */
+
+#define warning _glp_mpl_warning
+void warning(MPL *mpl, char *fmt, ...);
+/* print warning message and continue model processing */
+
+#define mpl_initialize _glp_mpl_initialize
+MPL *mpl_initialize(void);
+/* create and initialize translator database */
+
+#define mpl_read_model _glp_mpl_read_model
+int mpl_read_model(MPL *mpl, char *file, int skip_data);
+/* read model section and optional data section */
+
+#define mpl_read_data _glp_mpl_read_data
+int mpl_read_data(MPL *mpl, char *file);
+/* read data section */
+
+#define mpl_generate _glp_mpl_generate
+int mpl_generate(MPL *mpl, char *file);
+/* generate model */
+
+#define mpl_get_prob_name _glp_mpl_get_prob_name
+char *mpl_get_prob_name(MPL *mpl);
+/* obtain problem (model) name */
+
+#define mpl_get_num_rows _glp_mpl_get_num_rows
+int mpl_get_num_rows(MPL *mpl);
+/* determine number of rows */
+
+#define mpl_get_num_cols _glp_mpl_get_num_cols
+int mpl_get_num_cols(MPL *mpl);
+/* determine number of columns */
+
+#define mpl_get_row_name _glp_mpl_get_row_name
+char *mpl_get_row_name(MPL *mpl, int i);
+/* obtain row name */
+
+#define mpl_get_row_kind _glp_mpl_get_row_kind
+int mpl_get_row_kind(MPL *mpl, int i);
+/* determine row kind */
+
+#define mpl_get_row_bnds _glp_mpl_get_row_bnds
+int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
+/* obtain row bounds */
+
+#define mpl_get_mat_row _glp_mpl_get_mat_row
+int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
+/* obtain row of the constraint matrix */
+
+#define mpl_get_row_c0 _glp_mpl_get_row_c0
+double mpl_get_row_c0(MPL *mpl, int i);
+/* obtain constant term of free row */
+
+#define mpl_get_col_name _glp_mpl_get_col_name
+char *mpl_get_col_name(MPL *mpl, int j);
+/* obtain column name */
+
+#define mpl_get_col_kind _glp_mpl_get_col_kind
+int mpl_get_col_kind(MPL *mpl, int j);
+/* determine column kind */
+
+#define mpl_get_col_bnds _glp_mpl_get_col_bnds
+int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
+/* obtain column bounds */
+
+#define mpl_has_solve_stmt _glp_mpl_has_solve_stmt
+int mpl_has_solve_stmt(MPL *mpl);
+/* check if model has solve statement */
+
+#if 1 /* 15/V-2010 */
+#define mpl_put_row_soln _glp_mpl_put_row_soln
+void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
+      double dual);
+/* store row (constraint/objective) solution components */
+#endif
+
+#if 1 /* 15/V-2010 */
+#define mpl_put_col_soln _glp_mpl_put_col_soln
+void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
+      double dual);
+/* store column (variable) solution components */
+#endif
+
+#if 0 /* 15/V-2010 */
+#define mpl_put_col_value _glp_mpl_put_col_value
+void mpl_put_col_value(MPL *mpl, int j, double val);
+/* store column value */
+#endif
+
+#define mpl_postsolve _glp_mpl_postsolve
+int mpl_postsolve(MPL *mpl);
+/* postsolve model */
+
+#define mpl_terminate _glp_mpl_terminate
+void mpl_terminate(MPL *mpl);
+/* free all resources used by translator */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpmpl01.c
===================================================================
--- deps/glpk/src/glpmpl01.c	(revision 9)
+++ deps/glpk/src/glpmpl01.c	(revision 9)
@@ -0,0 +1,4715 @@
+/* glpmpl01.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_STDIO
+#include "glpmpl.h"
+#define dmp_get_atomv dmp_get_atom
+
+/**********************************************************************/
+/* * *                  PROCESSING MODEL SECTION                  * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- enter_context - enter current token into context queue.
+--
+-- This routine enters the current token into the context queue. */
+
+void enter_context(MPL *mpl)
+{     char *image, *s;
+      if (mpl->token == T_EOF)
+         image = "_|_";
+      else if (mpl->token == T_STRING)
+         image = "'...'";
+      else
+         image = mpl->image;
+      xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE);
+      mpl->context[mpl->c_ptr++] = ' ';
+      if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
+      for (s = image; *s != '\0'; s++)
+      {  mpl->context[mpl->c_ptr++] = *s;
+         if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- print_context - print current content of context queue.
+--
+-- This routine prints current content of the context queue. */
+
+void print_context(MPL *mpl)
+{     int c;
+      while (mpl->c_ptr > 0)
+      {  mpl->c_ptr--;
+         c = mpl->context[0];
+         memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1);
+         mpl->context[CONTEXT_SIZE-1] = (char)c;
+      }
+      xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...",
+         CONTEXT_SIZE, mpl->context);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- get_char - scan next character from input text file.
+--
+-- This routine scans a next ASCII character from the input text file.
+-- In case of end-of-file, the character is assigned EOF. */
+
+void get_char(MPL *mpl)
+{     int c;
+      if (mpl->c == EOF) goto done;
+      if (mpl->c == '\n') mpl->line++;
+      c = read_char(mpl);
+      if (c == EOF)
+      {  if (mpl->c == '\n')
+            mpl->line--;
+         else
+            warning(mpl, "final NL missing before end of file");
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+      {  enter_context(mpl);
+         error(mpl, "control character 0x%02X not allowed", c);
+      }
+      mpl->c = c;
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- append_char - append character to current token.
+--
+-- This routine appends the current character to the current token and
+-- then scans a next character. */
+
+void append_char(MPL *mpl)
+{     xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH);
+      if (mpl->imlen == MAX_LENGTH)
+      {  switch (mpl->token)
+         {  case T_NAME:
+               enter_context(mpl);
+               error(mpl, "symbolic name %s... too long", mpl->image);
+            case T_SYMBOL:
+               enter_context(mpl);
+               error(mpl, "symbol %s... too long", mpl->image);
+            case T_NUMBER:
+               enter_context(mpl);
+               error(mpl, "numeric literal %s... too long", mpl->image);
+            case T_STRING:
+               enter_context(mpl);
+               error(mpl, "string literal too long");
+            default:
+               xassert(mpl != mpl);
+         }
+      }
+      mpl->image[mpl->imlen++] = (char)mpl->c;
+      mpl->image[mpl->imlen] = '\0';
+      get_char(mpl);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- get_token - scan next token from input text file.
+--
+-- This routine scans a next token from the input text file using the
+-- standard finite automation technique. */
+
+void get_token(MPL *mpl)
+{     /* save the current token */
+      mpl->b_token = mpl->token;
+      mpl->b_imlen = mpl->imlen;
+      strcpy(mpl->b_image, mpl->image);
+      mpl->b_value = mpl->value;
+      /* if the next token is already scanned, make it current */
+      if (mpl->f_scan)
+      {  mpl->f_scan = 0;
+         mpl->token = mpl->f_token;
+         mpl->imlen = mpl->f_imlen;
+         strcpy(mpl->image, mpl->f_image);
+         mpl->value = mpl->f_value;
+         goto done;
+      }
+loop: /* nothing has been scanned so far */
+      mpl->token = 0;
+      mpl->imlen = 0;
+      mpl->image[0] = '\0';
+      mpl->value = 0.0;
+      /* skip any uninteresting characters */
+      while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl);
+      /* recognize and construct the token */
+      if (mpl->c == EOF)
+      {  /* end-of-file reached */
+         mpl->token = T_EOF;
+      }
+      else if (mpl->c == '#')
+      {  /* comment; skip anything until end-of-line */
+         while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl);
+         goto loop;
+      }
+      else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_'))
+      {  /* symbolic name or reserved keyword */
+         mpl->token = T_NAME;
+         while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl);
+         if (strcmp(mpl->image, "and") == 0)
+            mpl->token = T_AND;
+         else if (strcmp(mpl->image, "by") == 0)
+            mpl->token = T_BY;
+         else if (strcmp(mpl->image, "cross") == 0)
+            mpl->token = T_CROSS;
+         else if (strcmp(mpl->image, "diff") == 0)
+            mpl->token = T_DIFF;
+         else if (strcmp(mpl->image, "div") == 0)
+            mpl->token = T_DIV;
+         else if (strcmp(mpl->image, "else") == 0)
+            mpl->token = T_ELSE;
+         else if (strcmp(mpl->image, "if") == 0)
+            mpl->token = T_IF;
+         else if (strcmp(mpl->image, "in") == 0)
+            mpl->token = T_IN;
+#if 1 /* 21/VII-2006 */
+         else if (strcmp(mpl->image, "Infinity") == 0)
+            mpl->token = T_INFINITY;
+#endif
+         else if (strcmp(mpl->image, "inter") == 0)
+            mpl->token = T_INTER;
+         else if (strcmp(mpl->image, "less") == 0)
+            mpl->token = T_LESS;
+         else if (strcmp(mpl->image, "mod") == 0)
+            mpl->token = T_MOD;
+         else if (strcmp(mpl->image, "not") == 0)
+            mpl->token = T_NOT;
+         else if (strcmp(mpl->image, "or") == 0)
+            mpl->token = T_OR;
+         else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.')
+         {  mpl->token = T_SPTP;
+            append_char(mpl);
+            if (mpl->c != 't')
+sptp:       {  enter_context(mpl);
+               error(mpl, "keyword s.t. incomplete");
+            }
+            append_char(mpl);
+            if (mpl->c != '.') goto sptp;
+            append_char(mpl);
+         }
+         else if (strcmp(mpl->image, "symdiff") == 0)
+            mpl->token = T_SYMDIFF;
+         else if (strcmp(mpl->image, "then") == 0)
+            mpl->token = T_THEN;
+         else if (strcmp(mpl->image, "union") == 0)
+            mpl->token = T_UNION;
+         else if (strcmp(mpl->image, "within") == 0)
+            mpl->token = T_WITHIN;
+      }
+      else if (!mpl->flag_d && isdigit(mpl->c))
+      {  /* numeric literal */
+         mpl->token = T_NUMBER;
+         /* scan integer part */
+         while (isdigit(mpl->c)) append_char(mpl);
+         /* scan optional fractional part */
+         if (mpl->c == '.')
+         {  append_char(mpl);
+            if (mpl->c == '.')
+            {  /* hmm, it is not the fractional part, it is dots that
+                  follow the integer part */
+               mpl->imlen--;
+               mpl->image[mpl->imlen] = '\0';
+               mpl->f_dots = 1;
+               goto conv;
+            }
+frac:       while (isdigit(mpl->c)) append_char(mpl);
+         }
+         /* scan optional decimal exponent */
+         if (mpl->c == 'e' || mpl->c == 'E')
+         {  append_char(mpl);
+            if (mpl->c == '+' || mpl->c == '-') append_char(mpl);
+            if (!isdigit(mpl->c))
+            {  enter_context(mpl);
+               error(mpl, "numeric literal %s incomplete", mpl->image);
+            }
+            while (isdigit(mpl->c)) append_char(mpl);
+         }
+         /* there must be no letter following the numeric literal */
+         if (isalpha(mpl->c) || mpl->c == '_')
+         {  enter_context(mpl);
+            error(mpl, "symbol %s%c... should be enclosed in quotes",
+               mpl->image, mpl->c);
+         }
+conv:    /* convert numeric literal to floating-point */
+         if (str2num(mpl->image, &mpl->value))
+err:     {  enter_context(mpl);
+            error(mpl, "cannot convert numeric literal %s to floating-p"
+               "oint number", mpl->image);
+         }
+      }
+      else if (mpl->c == '\'' || mpl->c == '"')
+      {  /* character string */
+         int quote = mpl->c;
+         mpl->token = T_STRING;
+         get_char(mpl);
+         for (;;)
+         {  if (mpl->c == '\n' || mpl->c == EOF)
+            {  enter_context(mpl);
+               error(mpl, "unexpected end of line; string literal incom"
+                  "plete");
+            }
+            if (mpl->c == quote)
+            {  get_char(mpl);
+               if (mpl->c != quote) break;
+            }
+            append_char(mpl);
+         }
+      }
+      else if (!mpl->flag_d && mpl->c == '+')
+         mpl->token = T_PLUS, append_char(mpl);
+      else if (!mpl->flag_d && mpl->c == '-')
+         mpl->token = T_MINUS, append_char(mpl);
+      else if (mpl->c == '*')
+      {  mpl->token = T_ASTERISK, append_char(mpl);
+         if (mpl->c == '*')
+            mpl->token = T_POWER, append_char(mpl);
+      }
+      else if (mpl->c == '/')
+      {  mpl->token = T_SLASH, append_char(mpl);
+         if (mpl->c == '*')
+         {  /* comment sequence */
+            get_char(mpl);
+            for (;;)
+            {  if (mpl->c == EOF)
+               {  /* do not call enter_context at this point */
+                  error(mpl, "unexpected end of file; comment sequence "
+                     "incomplete");
+               }
+               else if (mpl->c == '*')
+               {  get_char(mpl);
+                  if (mpl->c == '/') break;
+               }
+               else
+                  get_char(mpl);
+            }
+            get_char(mpl);
+            goto loop;
+         }
+      }
+      else if (mpl->c == '^')
+         mpl->token = T_POWER, append_char(mpl);
+      else if (mpl->c == '<')
+      {  mpl->token = T_LT, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_LE, append_char(mpl);
+         else if (mpl->c == '>')
+            mpl->token = T_NE, append_char(mpl);
+#if 1 /* 11/II-2008 */
+         else if (mpl->c == '-')
+            mpl->token = T_INPUT, append_char(mpl);
+#endif
+      }
+      else if (mpl->c == '=')
+      {  mpl->token = T_EQ, append_char(mpl);
+         if (mpl->c == '=') append_char(mpl);
+      }
+      else if (mpl->c == '>')
+      {  mpl->token = T_GT, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_GE, append_char(mpl);
+#if 1 /* 14/VII-2006 */
+         else if (mpl->c == '>')
+            mpl->token = T_APPEND, append_char(mpl);
+#endif
+      }
+      else if (mpl->c == '!')
+      {  mpl->token = T_NOT, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_NE, append_char(mpl);
+      }
+      else if (mpl->c == '&')
+      {  mpl->token = T_CONCAT, append_char(mpl);
+         if (mpl->c == '&')
+            mpl->token = T_AND, append_char(mpl);
+      }
+      else if (mpl->c == '|')
+      {  mpl->token = T_BAR, append_char(mpl);
+         if (mpl->c == '|')
+            mpl->token = T_OR, append_char(mpl);
+      }
+      else if (!mpl->flag_d && mpl->c == '.')
+      {  mpl->token = T_POINT, append_char(mpl);
+         if (mpl->f_dots)
+         {  /* dots; the first dot was read on the previous call to the
+               scanner, so the current character is the second dot */
+            mpl->token = T_DOTS;
+            mpl->imlen = 2;
+            strcpy(mpl->image, "..");
+            mpl->f_dots = 0;
+         }
+         else if (mpl->c == '.')
+            mpl->token = T_DOTS, append_char(mpl);
+         else if (isdigit(mpl->c))
+         {  /* numeric literal that begins with the decimal point */
+            mpl->token = T_NUMBER, append_char(mpl);
+            goto frac;
+         }
+      }
+      else if (mpl->c == ',')
+         mpl->token = T_COMMA, append_char(mpl);
+      else if (mpl->c == ':')
+      {  mpl->token = T_COLON, append_char(mpl);
+         if (mpl->c == '=')
+            mpl->token = T_ASSIGN, append_char(mpl);
+      }
+      else if (mpl->c == ';')
+         mpl->token = T_SEMICOLON, append_char(mpl);
+      else if (mpl->c == '(')
+         mpl->token = T_LEFT, append_char(mpl);
+      else if (mpl->c == ')')
+         mpl->token = T_RIGHT, append_char(mpl);
+      else if (mpl->c == '[')
+         mpl->token = T_LBRACKET, append_char(mpl);
+      else if (mpl->c == ']')
+         mpl->token = T_RBRACKET, append_char(mpl);
+      else if (mpl->c == '{')
+         mpl->token = T_LBRACE, append_char(mpl);
+      else if (mpl->c == '}')
+         mpl->token = T_RBRACE, append_char(mpl);
+#if 1 /* 11/II-2008 */
+      else if (mpl->c == '~')
+         mpl->token = T_TILDE, append_char(mpl);
+#endif
+      else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
+      {  /* symbol */
+         xassert(mpl->flag_d);
+         mpl->token = T_SYMBOL;
+         while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
+            append_char(mpl);
+         switch (str2num(mpl->image, &mpl->value))
+         {  case 0:
+               mpl->token = T_NUMBER;
+               break;
+            case 1:
+               goto err;
+            case 2:
+               break;
+            default:
+               xassert(mpl != mpl);
+         }
+      }
+      else
+      {  enter_context(mpl);
+         error(mpl, "character %c not allowed", mpl->c);
+      }
+      /* enter the current token into the context queue */
+      enter_context(mpl);
+      /* reset the flag, which may be set by indexing_expression() and
+         is used by expression_list() */
+      mpl->flag_x = 0;
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- unget_token - return current token back to input stream.
+--
+-- This routine returns the current token back to the input stream, so
+-- the previously scanned token becomes the current one. */
+
+void unget_token(MPL *mpl)
+{     /* save the current token, which becomes the next one */
+      xassert(!mpl->f_scan);
+      mpl->f_scan = 1;
+      mpl->f_token = mpl->token;
+      mpl->f_imlen = mpl->imlen;
+      strcpy(mpl->f_image, mpl->image);
+      mpl->f_value = mpl->value;
+      /* restore the previous token, which becomes the current one */
+      mpl->token = mpl->b_token;
+      mpl->imlen = mpl->b_imlen;
+      strcpy(mpl->image, mpl->b_image);
+      mpl->value = mpl->b_value;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- is_keyword - check if current token is given non-reserved keyword.
+--
+-- If the current token is given (non-reserved) keyword, this routine
+-- returns non-zero. Otherwise zero is returned. */
+
+int is_keyword(MPL *mpl, char *keyword)
+{     return
+         mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0;
+}
+
+/*----------------------------------------------------------------------
+-- is_reserved - check if current token is reserved keyword.
+--
+-- If the current token is a reserved keyword, this routine returns
+-- non-zero. Otherwise zero is returned. */
+
+int is_reserved(MPL *mpl)
+{     return
+         mpl->token == T_AND && mpl->image[0] == 'a' ||
+         mpl->token == T_BY ||
+         mpl->token == T_CROSS ||
+         mpl->token == T_DIFF ||
+         mpl->token == T_DIV ||
+         mpl->token == T_ELSE ||
+         mpl->token == T_IF ||
+         mpl->token == T_IN ||
+         mpl->token == T_INTER ||
+         mpl->token == T_LESS ||
+         mpl->token == T_MOD ||
+         mpl->token == T_NOT && mpl->image[0] == 'n' ||
+         mpl->token == T_OR && mpl->image[0] == 'o' ||
+         mpl->token == T_SYMDIFF ||
+         mpl->token == T_THEN ||
+         mpl->token == T_UNION ||
+         mpl->token == T_WITHIN;
+}
+
+/*----------------------------------------------------------------------
+-- make_code - generate pseudo-code (basic routine).
+--
+-- This routine generates specified pseudo-code. It is assumed that all
+-- other translator routines use this basic routine. */
+
+CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim)
+{     CODE *code;
+      DOMAIN *domain;
+      DOMAIN_BLOCK *block;
+      ARG_LIST *e;
+      /* generate pseudo-code */
+      code = alloc(CODE);
+      code->op = op;
+      code->vflag = 0; /* is inherited from operand(s) */
+      /* copy operands and also make them referring to the pseudo-code
+         being generated, because the latter becomes the parent for all
+         its operands */
+      memset(&code->arg, '?', sizeof(OPERANDS));
+      switch (op)
+      {  case O_NUMBER:
+            code->arg.num = arg->num;
+            break;
+         case O_STRING:
+            code->arg.str = arg->str;
+            break;
+         case O_INDEX:
+            code->arg.index.slot = arg->index.slot;
+            code->arg.index.next = arg->index.next;
+            break;
+         case O_MEMNUM:
+         case O_MEMSYM:
+            for (e = arg->par.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.par.par = arg->par.par;
+            code->arg.par.list = arg->par.list;
+            break;
+         case O_MEMSET:
+            for (e = arg->set.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.set.set = arg->set.set;
+            code->arg.set.list = arg->set.list;
+            break;
+         case O_MEMVAR:
+            for (e = arg->var.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.var.var = arg->var.var;
+            code->arg.var.list = arg->var.list;
+#if 1 /* 15/V-2010 */
+            code->arg.var.suff = arg->var.suff;
+#endif
+            break;
+#if 1 /* 15/V-2010 */
+         case O_MEMCON:
+            for (e = arg->con.list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.con.con = arg->con.con;
+            code->arg.con.list = arg->con.list;
+            code->arg.con.suff = arg->con.suff;
+            break;
+#endif
+         case O_TUPLE:
+         case O_MAKE:
+            for (e = arg->list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.list = arg->list;
+            break;
+         case O_SLICE:
+            xassert(arg->slice != NULL);
+            code->arg.slice = arg->slice;
+            break;
+         case O_IRAND224:
+         case O_UNIFORM01:
+         case O_NORMAL01:
+         case O_GMTIME:
+            code->vflag = 1;
+            break;
+         case O_CVTNUM:
+         case O_CVTSYM:
+         case O_CVTLOG:
+         case O_CVTTUP:
+         case O_CVTLFM:
+         case O_PLUS:
+         case O_MINUS:
+         case O_NOT:
+         case O_ABS:
+         case O_CEIL:
+         case O_FLOOR:
+         case O_EXP:
+         case O_LOG:
+         case O_LOG10:
+         case O_SQRT:
+         case O_SIN:
+         case O_COS:
+         case O_ATAN:
+         case O_ROUND:
+         case O_TRUNC:
+         case O_CARD:
+         case O_LENGTH:
+            /* unary operation */
+            xassert(arg->arg.x != NULL);
+            xassert(arg->arg.x->up == NULL);
+            arg->arg.x->up = code;
+            code->vflag |= arg->arg.x->vflag;
+            code->arg.arg.x = arg->arg.x;
+            break;
+         case O_ADD:
+         case O_SUB:
+         case O_LESS:
+         case O_MUL:
+         case O_DIV:
+         case O_IDIV:
+         case O_MOD:
+         case O_POWER:
+         case O_ATAN2:
+         case O_ROUND2:
+         case O_TRUNC2:
+         case O_UNIFORM:
+            if (op == O_UNIFORM) code->vflag = 1;
+         case O_NORMAL:
+            if (op == O_NORMAL) code->vflag = 1;
+         case O_CONCAT:
+         case O_LT:
+         case O_LE:
+         case O_EQ:
+         case O_GE:
+         case O_GT:
+         case O_NE:
+         case O_AND:
+         case O_OR:
+         case O_UNION:
+         case O_DIFF:
+         case O_SYMDIFF:
+         case O_INTER:
+         case O_CROSS:
+         case O_IN:
+         case O_NOTIN:
+         case O_WITHIN:
+         case O_NOTWITHIN:
+         case O_SUBSTR:
+         case O_STR2TIME:
+         case O_TIME2STR:
+            /* binary operation */
+            xassert(arg->arg.x != NULL);
+            xassert(arg->arg.x->up == NULL);
+            arg->arg.x->up = code;
+            code->vflag |= arg->arg.x->vflag;
+            xassert(arg->arg.y != NULL);
+            xassert(arg->arg.y->up == NULL);
+            arg->arg.y->up = code;
+            code->vflag |= arg->arg.y->vflag;
+            code->arg.arg.x = arg->arg.x;
+            code->arg.arg.y = arg->arg.y;
+            break;
+         case O_DOTS:
+         case O_FORK:
+         case O_SUBSTR3:
+            /* ternary operation */
+            xassert(arg->arg.x != NULL);
+            xassert(arg->arg.x->up == NULL);
+            arg->arg.x->up = code;
+            code->vflag |= arg->arg.x->vflag;
+            xassert(arg->arg.y != NULL);
+            xassert(arg->arg.y->up == NULL);
+            arg->arg.y->up = code;
+            code->vflag |= arg->arg.y->vflag;
+            if (arg->arg.z != NULL)
+            {  xassert(arg->arg.z->up == NULL);
+               arg->arg.z->up = code;
+               code->vflag |= arg->arg.z->vflag;
+            }
+            code->arg.arg.x = arg->arg.x;
+            code->arg.arg.y = arg->arg.y;
+            code->arg.arg.z = arg->arg.z;
+            break;
+         case O_MIN:
+         case O_MAX:
+            /* n-ary operation */
+            for (e = arg->list; e != NULL; e = e->next)
+            {  xassert(e->x != NULL);
+               xassert(e->x->up == NULL);
+               e->x->up = code;
+               code->vflag |= e->x->vflag;
+            }
+            code->arg.list = arg->list;
+            break;
+         case O_SUM:
+         case O_PROD:
+         case O_MINIMUM:
+         case O_MAXIMUM:
+         case O_FORALL:
+         case O_EXISTS:
+         case O_SETOF:
+         case O_BUILD:
+            /* iterated operation */
+            domain = arg->loop.domain;
+            xassert(domain != NULL);
+            if (domain->code != NULL)
+            {  xassert(domain->code->up == NULL);
+               domain->code->up = code;
+               code->vflag |= domain->code->vflag;
+            }
+            for (block = domain->list; block != NULL; block =
+               block->next)
+            {  xassert(block->code != NULL);
+               xassert(block->code->up == NULL);
+               block->code->up = code;
+               code->vflag |= block->code->vflag;
+            }
+            if (arg->loop.x != NULL)
+            {  xassert(arg->loop.x->up == NULL);
+               arg->loop.x->up = code;
+               code->vflag |= arg->loop.x->vflag;
+            }
+            code->arg.loop.domain = arg->loop.domain;
+            code->arg.loop.x = arg->loop.x;
+            break;
+         default:
+            xassert(op != op);
+      }
+      /* set other attributes of the pseudo-code */
+      code->type = type;
+      code->dim = dim;
+      code->up = NULL;
+      code->valid = 0;
+      memset(&code->value, '?', sizeof(VALUE));
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_unary - generate pseudo-code for unary operation.
+--
+-- This routine generates pseudo-code for unary operation. */
+
+CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(x != NULL);
+      arg.arg.x = x;
+      code = make_code(mpl, op, &arg, type, dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_binary - generate pseudo-code for binary operation.
+--
+-- This routine generates pseudo-code for binary operation. */
+
+CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
+      int dim)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(x != NULL);
+      xassert(y != NULL);
+      arg.arg.x = x;
+      arg.arg.y = y;
+      code = make_code(mpl, op, &arg, type, dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- make_ternary - generate pseudo-code for ternary operation.
+--
+-- This routine generates pseudo-code for ternary operation. */
+
+CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
+      int type, int dim)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(x != NULL);
+      xassert(y != NULL);
+      /* third operand can be NULL */
+      arg.arg.x = x;
+      arg.arg.y = y;
+      arg.arg.z = z;
+      code = make_code(mpl, op, &arg, type, dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- numeric_literal - parse reference to numeric literal.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <numeric literal> */
+
+CODE *numeric_literal(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(mpl->token == T_NUMBER);
+      arg.num = mpl->value;
+      code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
+      get_token(mpl /* <numeric literal> */);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- string_literal - parse reference to string literal.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <string literal> */
+
+CODE *string_literal(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(mpl->token == T_STRING);
+      arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(arg.str, mpl->image);
+      code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0);
+      get_token(mpl /* <string literal> */);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- create_arg_list - create empty operands list.
+--
+-- This routine creates operands list, which is initially empty. */
+
+ARG_LIST *create_arg_list(MPL *mpl)
+{     ARG_LIST *list;
+      xassert(mpl == mpl);
+      list = NULL;
+      return list;
+}
+
+/*----------------------------------------------------------------------
+-- expand_arg_list - append operand to operands list.
+--
+-- This routine appends new operand to specified operands list. */
+
+ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x)
+{     ARG_LIST *tail, *temp;
+      xassert(x != NULL);
+      /* create new operands list entry */
+      tail = alloc(ARG_LIST);
+      tail->x = x;
+      tail->next = NULL;
+      /* and append it to the operands list */
+      if (list == NULL)
+         list = tail;
+      else
+      {  for (temp = list; temp->next != NULL; temp = temp->next);
+         temp->next = tail;
+      }
+      return list;
+}
+
+/*----------------------------------------------------------------------
+-- arg_list_len - determine length of operands list.
+--
+-- This routine returns the number of operands in operands list. */
+
+int arg_list_len(MPL *mpl, ARG_LIST *list)
+{     ARG_LIST *temp;
+      int len;
+      xassert(mpl == mpl);
+      len = 0;
+      for (temp = list; temp != NULL; temp = temp->next) len++;
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- subscript_list - parse subscript list.
+--
+-- This routine parses subscript list using the syntax:
+--
+-- <subscript list> ::= <subscript>
+-- <subscript list> ::= <subscript list> , <subscript>
+-- <subscript> ::= <expression 5> */
+
+ARG_LIST *subscript_list(MPL *mpl)
+{     ARG_LIST *list;
+      CODE *x;
+      list = create_arg_list(mpl);
+      for (;;)
+      {  /* parse subscript expression */
+         x = expression_5(mpl);
+         /* convert it to symbolic type, if necessary */
+         if (x->type == A_NUMERIC)
+            x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+         /* check that now the expression is of symbolic type */
+         if (x->type != A_SYMBOLIC)
+            error(mpl, "subscript expression has invalid type");
+         xassert(x->dim == 0);
+         /* and append it to the subscript list */
+         list = expand_arg_list(mpl, list, x);
+         /* check a token that follows the subscript expression */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RBRACKET)
+            break;
+         else
+            error(mpl, "syntax error in subscript list");
+      }
+      return list;
+}
+
+#if 1 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- object_reference - parse reference to named object.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <dummy index>
+-- <primary expression> ::= <set name>
+-- <primary expression> ::= <set name> [ <subscript list> ]
+-- <primary expression> ::= <parameter name>
+-- <primary expression> ::= <parameter name> [ <subscript list> ]
+-- <primary expression> ::= <variable name> <suffix>
+-- <primary expression> ::= <variable name> [ <subscript list> ]
+--                          <suffix>
+-- <primary expression> ::= <constraint name> <suffix>
+-- <primary expression> ::= <constraint name> [ <subscript list> ]
+--                          <suffix>
+-- <dummy index> ::= <symbolic name>
+-- <set name> ::= <symbolic name>
+-- <parameter name> ::= <symbolic name>
+-- <variable name> ::= <symbolic name>
+-- <constraint name> ::= <symbolic name>
+-- <suffix> ::= <empty> | .lb | .ub | .status | .val | .dual */
+
+CODE *object_reference(MPL *mpl)
+{     AVLNODE *node;
+      DOMAIN_SLOT *slot;
+      SET *set;
+      PARAMETER *par;
+      VARIABLE *var;
+      CONSTRAINT *con;
+      ARG_LIST *list;
+      OPERANDS arg;
+      CODE *code;
+      char *name;
+      int dim, suff;
+      /* find the object in the symbolic name table */
+      xassert(mpl->token == T_NAME);
+      node = avl_find_node(mpl->tree, mpl->image);
+      if (node == NULL)
+         error(mpl, "%s not defined", mpl->image);
+      /* check the object type and obtain its dimension */
+      switch (avl_get_node_type(node))
+      {  case A_INDEX:
+            /* dummy index */
+            slot = (DOMAIN_SLOT *)avl_get_node_link(node);
+            name = slot->name;
+            dim = 0;
+            break;
+         case A_SET:
+            /* model set */
+            set = (SET *)avl_get_node_link(node);
+            name = set->name;
+            dim = set->dim;
+            /* if a set object is referenced in its own declaration and
+               the dimen attribute is not specified yet, use dimen 1 by
+               default */
+            if (set->dimen == 0) set->dimen = 1;
+            break;
+         case A_PARAMETER:
+            /* model parameter */
+            par = (PARAMETER *)avl_get_node_link(node);
+            name = par->name;
+            dim = par->dim;
+            break;
+         case A_VARIABLE:
+            /* model variable */
+            var = (VARIABLE *)avl_get_node_link(node);
+            name = var->name;
+            dim = var->dim;
+            break;
+         case A_CONSTRAINT:
+            /* model constraint or objective */
+            con = (CONSTRAINT *)avl_get_node_link(node);
+            name = con->name;
+            dim = con->dim;
+            break;
+         default:
+            xassert(node != node);
+      }
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional subscript list */
+      if (mpl->token == T_LBRACKET)
+      {  /* subscript list is specified */
+         if (dim == 0)
+            error(mpl, "%s cannot be subscripted", name);
+         get_token(mpl /* [ */);
+         list = subscript_list(mpl);
+         if (dim != arg_list_len(mpl, list))
+            error(mpl, "%s must have %d subscript%s rather than %d",
+               name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list));
+         xassert(mpl->token == T_RBRACKET);
+         get_token(mpl /* ] */);
+      }
+      else
+      {  /* subscript list is not specified */
+         if (dim != 0)
+            error(mpl, "%s must be subscripted", name);
+         list = create_arg_list(mpl);
+      }
+      /* parse optional suffix */
+      if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE)
+         suff = DOT_NONE;
+      else
+         suff = DOT_VAL;
+      if (mpl->token == T_POINT)
+      {  get_token(mpl /* . */);
+         if (mpl->token != T_NAME)
+            error(mpl, "invalid use of period");
+         if (!(avl_get_node_type(node) == A_VARIABLE ||
+               avl_get_node_type(node) == A_CONSTRAINT))
+            error(mpl, "%s cannot have a suffix", name);
+         if (strcmp(mpl->image, "lb") == 0)
+            suff = DOT_LB;
+         else if (strcmp(mpl->image, "ub") == 0)
+            suff = DOT_UB;
+         else if (strcmp(mpl->image, "status") == 0)
+            suff = DOT_STATUS;
+         else if (strcmp(mpl->image, "val") == 0)
+            suff = DOT_VAL;
+         else if (strcmp(mpl->image, "dual") == 0)
+            suff = DOT_DUAL;
+         else
+            error(mpl, "suffix .%s invalid", mpl->image);
+         get_token(mpl /* suffix */);
+      }
+      /* generate pseudo-code to take value of the object */
+      switch (avl_get_node_type(node))
+      {  case A_INDEX:
+            arg.index.slot = slot;
+            arg.index.next = slot->list;
+            code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0);
+            slot->list = code;
+            break;
+         case A_SET:
+            arg.set.set = set;
+            arg.set.list = list;
+            code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET,
+               set->dimen);
+            break;
+         case A_PARAMETER:
+            arg.par.par = par;
+            arg.par.list = list;
+            if (par->type == A_SYMBOLIC)
+               code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0);
+            else
+               code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0);
+            break;
+         case A_VARIABLE:
+            if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
+               || suff == DOT_DUAL))
+               error(mpl, "invalid reference to status, primal value, o"
+                  "r dual value of variable %s above solve statement",
+                  var->name);
+            arg.var.var = var;
+            arg.var.list = list;
+            arg.var.suff = suff;
+            code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ?
+               A_FORMULA : A_NUMERIC, 0);
+            break;
+         case A_CONSTRAINT:
+            if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
+               || suff == DOT_DUAL))
+               error(mpl, "invalid reference to status, primal value, o"
+                  "r dual value of %s %s above solve statement",
+                  con->type == A_CONSTRAINT ? "constraint" : "objective"
+                  , con->name);
+            arg.con.con = con;
+            arg.con.list = list;
+            arg.con.suff = suff;
+            code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0);
+            break;
+         default:
+            xassert(node != node);
+      }
+      return code;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- numeric_argument - parse argument passed to built-in function.
+--
+-- This routine parses an argument passed to numeric built-in function
+-- using the syntax:
+--
+-- <arg> ::= <expression 5> */
+
+CODE *numeric_argument(MPL *mpl, char *func)
+{     CODE *x;
+      x = expression_5(mpl);
+      /* convert the argument to numeric type, if necessary */
+      if (x->type == A_SYMBOLIC)
+         x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+      /* check that now the argument is of numeric type */
+      if (x->type != A_NUMERIC)
+         error(mpl, "argument for %s has invalid type", func);
+      xassert(x->dim == 0);
+      return x;
+}
+
+#if 1 /* 15/VII-2006 */
+CODE *symbolic_argument(MPL *mpl, char *func)
+{     CODE *x;
+      x = expression_5(mpl);
+      /* convert the argument to symbolic type, if necessary */
+      if (x->type == A_NUMERIC)
+         x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+      /* check that now the argument is of symbolic type */
+      if (x->type != A_SYMBOLIC)
+         error(mpl, "argument for %s has invalid type", func);
+      xassert(x->dim == 0);
+      return x;
+}
+#endif
+
+#if 1 /* 15/VII-2006 */
+CODE *elemset_argument(MPL *mpl, char *func)
+{     CODE *x;
+      x = expression_9(mpl);
+      if (x->type != A_ELEMSET)
+         error(mpl, "argument for %s has invalid type", func);
+      xassert(x->dim > 0);
+      return x;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- function_reference - parse reference to built-in function.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= abs ( <arg> )
+-- <primary expression> ::= ceil ( <arg> )
+-- <primary expression> ::= floor ( <arg> )
+-- <primary expression> ::= exp ( <arg> )
+-- <primary expression> ::= log ( <arg> )
+-- <primary expression> ::= log10 ( <arg> )
+-- <primary expression> ::= max ( <arg list> )
+-- <primary expression> ::= min ( <arg list> )
+-- <primary expression> ::= sqrt ( <arg> )
+-- <primary expression> ::= sin ( <arg> )
+-- <primary expression> ::= cos ( <arg> )
+-- <primary expression> ::= atan ( <arg> )
+-- <primary expression> ::= atan2 ( <arg> , <arg> )
+-- <primary expression> ::= round ( <arg> )
+-- <primary expression> ::= round ( <arg> , <arg> )
+-- <primary expression> ::= trunc ( <arg> )
+-- <primary expression> ::= trunc ( <arg> , <arg> )
+-- <primary expression> ::= Irand224 ( )
+-- <primary expression> ::= Uniform01 ( )
+-- <primary expression> ::= Uniform ( <arg> , <arg> )
+-- <primary expression> ::= Normal01 ( )
+-- <primary expression> ::= Normal ( <arg> , <arg> )
+-- <primary expression> ::= card ( <arg> )
+-- <primary expression> ::= length ( <arg> )
+-- <primary expression> ::= substr ( <arg> , <arg> )
+-- <primary expression> ::= substr ( <arg> , <arg> , <arg> )
+-- <primary expression> ::= str2time ( <arg> , <arg> )
+-- <primary expression> ::= time2str ( <arg> , <arg> )
+-- <primary expression> ::= gmtime ( )
+-- <arg list> ::= <arg>
+-- <arg list> ::= <arg list> , <arg> */
+
+CODE *function_reference(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      int op;
+      char func[15+1];
+      /* determine operation code */
+      xassert(mpl->token == T_NAME);
+      if (strcmp(mpl->image, "abs") == 0)
+         op = O_ABS;
+      else if (strcmp(mpl->image, "ceil") == 0)
+         op = O_CEIL;
+      else if (strcmp(mpl->image, "floor") == 0)
+         op = O_FLOOR;
+      else if (strcmp(mpl->image, "exp") == 0)
+         op = O_EXP;
+      else if (strcmp(mpl->image, "log") == 0)
+         op = O_LOG;
+      else if (strcmp(mpl->image, "log10") == 0)
+         op = O_LOG10;
+      else if (strcmp(mpl->image, "sqrt") == 0)
+         op = O_SQRT;
+      else if (strcmp(mpl->image, "sin") == 0)
+         op = O_SIN;
+      else if (strcmp(mpl->image, "cos") == 0)
+         op = O_COS;
+      else if (strcmp(mpl->image, "atan") == 0)
+         op = O_ATAN;
+      else if (strcmp(mpl->image, "min") == 0)
+         op = O_MIN;
+      else if (strcmp(mpl->image, "max") == 0)
+         op = O_MAX;
+      else if (strcmp(mpl->image, "round") == 0)
+         op = O_ROUND;
+      else if (strcmp(mpl->image, "trunc") == 0)
+         op = O_TRUNC;
+      else if (strcmp(mpl->image, "Irand224") == 0)
+         op = O_IRAND224;
+      else if (strcmp(mpl->image, "Uniform01") == 0)
+         op = O_UNIFORM01;
+      else if (strcmp(mpl->image, "Uniform") == 0)
+         op = O_UNIFORM;
+      else if (strcmp(mpl->image, "Normal01") == 0)
+         op = O_NORMAL01;
+      else if (strcmp(mpl->image, "Normal") == 0)
+         op = O_NORMAL;
+      else if (strcmp(mpl->image, "card") == 0)
+         op = O_CARD;
+      else if (strcmp(mpl->image, "length") == 0)
+         op = O_LENGTH;
+      else if (strcmp(mpl->image, "substr") == 0)
+         op = O_SUBSTR;
+      else if (strcmp(mpl->image, "str2time") == 0)
+         op = O_STR2TIME;
+      else if (strcmp(mpl->image, "time2str") == 0)
+         op = O_TIME2STR;
+      else if (strcmp(mpl->image, "gmtime") == 0)
+         op = O_GMTIME;
+      else
+         error(mpl, "function %s unknown", mpl->image);
+      /* save symbolic name of the function */
+      strcpy(func, mpl->image);
+      xassert(strlen(func) < sizeof(func));
+      get_token(mpl /* <symbolic name> */);
+      /* check the left parenthesis that follows the function name */
+      xassert(mpl->token == T_LEFT);
+      get_token(mpl /* ( */);
+      /* parse argument list */
+      if (op == O_MIN || op == O_MAX)
+      {  /* min and max allow arbitrary number of arguments */
+         arg.list = create_arg_list(mpl);
+         /* parse argument list */
+         for (;;)
+         {  /* parse argument and append it to the operands list */
+            arg.list = expand_arg_list(mpl, arg.list,
+               numeric_argument(mpl, func));
+            /* check a token that follows the argument */
+            if (mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+            else if (mpl->token == T_RIGHT)
+               break;
+            else
+               error(mpl, "syntax error in argument list for %s", func);
+         }
+      }
+      else if (op == O_IRAND224 || op == O_UNIFORM01 || op ==
+         O_NORMAL01 || op == O_GMTIME)
+      {  /* Irand224, Uniform01, Normal01, gmtime need no arguments */
+         if (mpl->token != T_RIGHT)
+            error(mpl, "%s needs no arguments", func);
+      }
+      else if (op == O_UNIFORM || op == O_NORMAL)
+      {  /* Uniform and Normal need two arguments */
+         /* parse the first argument */
+         arg.arg.x = numeric_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = numeric_argument(mpl, func);
+         /* check a token that follows the second argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC)
+      {  /* atan, round, and trunc need one or two arguments */
+         /* parse the first argument */
+         arg.arg.x = numeric_argument(mpl, func);
+         /* parse the second argument, if specified */
+         if (mpl->token == T_COMMA)
+         {  switch (op)
+            {  case O_ATAN:  op = O_ATAN2;  break;
+               case O_ROUND: op = O_ROUND2; break;
+               case O_TRUNC: op = O_TRUNC2; break;
+               default: xassert(op != op);
+            }
+            get_token(mpl /* , */);
+            arg.arg.y = numeric_argument(mpl, func);
+         }
+         /* check a token that follows the last argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs one or two arguments", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_SUBSTR)
+      {  /* substr needs two or three arguments */
+         /* parse the first argument */
+         arg.arg.x = symbolic_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two or three arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = numeric_argument(mpl, func);
+         /* parse the third argument, if specified */
+         if (mpl->token == T_COMMA)
+         {  op = O_SUBSTR3;
+            get_token(mpl /* , */);
+            arg.arg.z = numeric_argument(mpl, func);
+         }
+         /* check a token that follows the last argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two or three arguments", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_STR2TIME)
+      {  /* str2time needs two arguments, both symbolic */
+         /* parse the first argument */
+         arg.arg.x = symbolic_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = symbolic_argument(mpl, func);
+         /* check a token that follows the second argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else if (op == O_TIME2STR)
+      {  /* time2str needs two arguments, numeric and symbolic */
+         /* parse the first argument */
+         arg.arg.x = numeric_argument(mpl, func);
+         /* check a token that follows the first argument */
+         if (mpl->token == T_COMMA)
+            ;
+         else if (mpl->token == T_RIGHT)
+            error(mpl, "%s needs two arguments", func);
+         else
+            error(mpl, "syntax error in argument for %s", func);
+         get_token(mpl /* , */);
+         /* parse the second argument */
+         arg.arg.y = symbolic_argument(mpl, func);
+         /* check a token that follows the second argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs two argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      else
+      {  /* other functions need one argument */
+         if (op == O_CARD)
+            arg.arg.x = elemset_argument(mpl, func);
+         else if (op == O_LENGTH)
+            arg.arg.x = symbolic_argument(mpl, func);
+         else
+            arg.arg.x = numeric_argument(mpl, func);
+         /* check a token that follows the argument */
+         if (mpl->token == T_COMMA)
+            error(mpl, "%s needs one argument", func);
+         else if (mpl->token == T_RIGHT)
+            ;
+         else
+            error(mpl, "syntax error in argument for %s", func);
+      }
+      /* make pseudo-code to call the built-in function */
+      if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR)
+         code = make_code(mpl, op, &arg, A_SYMBOLIC, 0);
+      else
+         code = make_code(mpl, op, &arg, A_NUMERIC, 0);
+      /* the reference ends with the right parenthesis */
+      xassert(mpl->token == T_RIGHT);
+      get_token(mpl /* ) */);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- create_domain - create empty domain.
+--
+-- This routine creates empty domain, which is initially empty, i.e.
+-- has no domain blocks. */
+
+DOMAIN *create_domain(MPL *mpl)
+{     DOMAIN *domain;
+      domain = alloc(DOMAIN);
+      domain->list = NULL;
+      domain->code = NULL;
+      return domain;
+}
+
+/*----------------------------------------------------------------------
+-- create_block - create empty domain block.
+--
+-- This routine creates empty domain block, which is initially empty,
+-- i.e. has no domain slots. */
+
+DOMAIN_BLOCK *create_block(MPL *mpl)
+{     DOMAIN_BLOCK *block;
+      block = alloc(DOMAIN_BLOCK);
+      block->list = NULL;
+      block->code = NULL;
+      block->backup = NULL;
+      block->next = NULL;
+      return block;
+}
+
+/*----------------------------------------------------------------------
+-- append_block - append domain block to specified domain.
+--
+-- This routine adds given domain block to the end of the block list of
+-- specified domain. */
+
+void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block)
+{     DOMAIN_BLOCK *temp;
+      xassert(mpl == mpl);
+      xassert(domain != NULL);
+      xassert(block != NULL);
+      xassert(block->next == NULL);
+      if (domain->list == NULL)
+         domain->list = block;
+      else
+      {  for (temp = domain->list; temp->next != NULL; temp =
+            temp->next);
+         temp->next = block;
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- append_slot - create and append new slot to domain block.
+--
+-- This routine creates new domain slot and adds it to the end of slot
+-- list of specified domain block.
+--
+-- The parameter name is symbolic name of the dummy index associated
+-- with the slot (the character string must be allocated). NULL means
+-- the dummy index is not explicitly specified.
+--
+-- The parameter code is pseudo-code for computing symbolic value, at
+-- which the dummy index is bounded. NULL means the dummy index is free
+-- in the domain scope. */
+
+DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
+      CODE *code)
+{     DOMAIN_SLOT *slot, *temp;
+      xassert(block != NULL);
+      slot = alloc(DOMAIN_SLOT);
+      slot->name = name;
+      slot->code = code;
+      slot->value = NULL;
+      slot->list = NULL;
+      slot->next = NULL;
+      if (block->list == NULL)
+         block->list = slot;
+      else
+      {  for (temp = block->list; temp->next != NULL; temp =
+            temp->next);
+         temp->next = slot;
+      }
+      return slot;
+}
+
+/*----------------------------------------------------------------------
+-- expression_list - parse expression list.
+--
+-- This routine parses a list of one or more expressions enclosed into
+-- the parentheses using the syntax:
+--
+-- <primary expression> ::= ( <expression list> )
+-- <expression list> ::= <expression 13>
+-- <expression list> ::= <expression 13> , <expression list>
+--
+-- Note that this construction may have three different meanings:
+--
+-- 1. If <expression list> consists of only one expression, <primary
+--    expression> is a parenthesized expression, which may be of any
+--    valid type (not necessarily 1-tuple).
+--
+-- 2. If <expression list> consists of several expressions separated by
+--    commae, where no expression is undeclared symbolic name, <primary
+--    expression> is a n-tuple.
+--
+-- 3. If <expression list> consists of several expressions separated by
+--    commae, where at least one expression is undeclared symbolic name
+--    (that denotes a dummy index), <primary expression> is a slice and
+--    can be only used as constituent of indexing expression. */
+
+#define max_dim 20
+/* maximal number of components allowed within parentheses */
+
+CODE *expression_list(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      struct { char *name; CODE *code; } list[1+max_dim];
+      int flag_x, next_token, dim, j, slice = 0;
+      xassert(mpl->token == T_LEFT);
+      /* the flag, which allows recognizing undeclared symbolic names
+         as dummy indices, will be automatically reset by get_token(),
+         so save it before scanning the next token */
+      flag_x = mpl->flag_x;
+      get_token(mpl /* ( */);
+      /* parse <expression list> */
+      for (dim = 1; ; dim++)
+      {  if (dim > max_dim)
+            error(mpl, "too many components within parentheses");
+         /* current component of <expression list> can be either dummy
+            index or expression */
+         if (mpl->token == T_NAME)
+         {  /* symbolic name is recognized as dummy index only if:
+               the flag, which allows that, is set, and
+               the name is followed by comma or right parenthesis, and
+               the name is undeclared */
+            get_token(mpl /* <symbolic name> */);
+            next_token = mpl->token;
+            unget_token(mpl);
+            if (!(flag_x &&
+                  (next_token == T_COMMA || next_token == T_RIGHT) &&
+                  avl_find_node(mpl->tree, mpl->image) == NULL))
+            {  /* this is not dummy index */
+               goto expr;
+            }
+            /* all dummy indices within the same slice must have unique
+               symbolic names */
+            for (j = 1; j < dim; j++)
+            {  if (list[j].name != NULL && strcmp(list[j].name,
+                  mpl->image) == 0)
+                  error(mpl, "duplicate dummy index %s not allowed",
+                     mpl->image);
+            }
+            /* current component of <expression list> is dummy index */
+            list[dim].name
+               = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+            strcpy(list[dim].name, mpl->image);
+            list[dim].code = NULL;
+            get_token(mpl /* <symbolic name> */);
+            /* <expression list> is a slice, because at least one dummy
+               index has appeared */
+            slice = 1;
+            /* note that the context ( <dummy index> ) is not allowed,
+               i.e. in this case <primary expression> is considered as
+               a parenthesized expression */
+            if (dim == 1 && mpl->token == T_RIGHT)
+               error(mpl, "%s not defined", list[dim].name);
+         }
+         else
+expr:    {  /* current component of <expression list> is expression */
+            code = expression_13(mpl);
+            /* if the current expression is followed by comma or it is
+               not the very first expression, entire <expression list>
+               is n-tuple or slice, in which case the current expression
+               should be converted to symbolic type, if necessary */
+            if (mpl->token == T_COMMA || dim > 1)
+            {  if (code->type == A_NUMERIC)
+                  code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
+               /* now the expression must be of symbolic type */
+               if (code->type != A_SYMBOLIC)
+                  error(mpl, "component expression has invalid type");
+               xassert(code->dim == 0);
+            }
+            list[dim].name = NULL;
+            list[dim].code = code;
+         }
+         /* check a token that follows the current component */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RIGHT)
+            break;
+         else
+            error(mpl, "right parenthesis missing where expected");
+      }
+      /* generate pseudo-code for <primary expression> */
+      if (dim == 1 && !slice)
+      {  /* <primary expression> is a parenthesized expression */
+         code = list[1].code;
+      }
+      else if (!slice)
+      {  /* <primary expression> is a n-tuple */
+         arg.list = create_arg_list(mpl);
+         for (j = 1; j <= dim; j++)
+            arg.list = expand_arg_list(mpl, arg.list, list[j].code);
+         code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim);
+      }
+      else
+      {  /* <primary expression> is a slice */
+         arg.slice = create_block(mpl);
+         for (j = 1; j <= dim; j++)
+            append_slot(mpl, arg.slice, list[j].name, list[j].code);
+         /* note that actually pseudo-codes with op = O_SLICE are never
+            evaluated */
+         code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim);
+      }
+      get_token(mpl /* ) */);
+      /* if <primary expression> is a slice, there must be the keyword
+         'in', which follows the right parenthesis */
+      if (slice && mpl->token != T_IN)
+         error(mpl, "keyword in missing where expected");
+      /* if the slice flag is set and there is the keyword 'in', which
+         follows <primary expression>, the latter must be a slice */
+      if (flag_x && mpl->token == T_IN && !slice)
+      {  if (dim == 1)
+            error(mpl, "syntax error in indexing expression");
+         else
+            error(mpl, "0-ary slice not allowed");
+      }
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- literal set - parse literal set.
+--
+-- This routine parses literal set using the syntax:
+--
+-- <literal set> ::= { <member list> }
+-- <member list> ::= <member expression>
+-- <member list> ::= <member list> , <member expression>
+-- <member expression> ::= <expression 5>
+--
+-- It is assumed that the left curly brace and the very first member
+-- expression that follows it are already parsed. The right curly brace
+-- remains unscanned on exit. */
+
+CODE *literal_set(MPL *mpl, CODE *code)
+{     OPERANDS arg;
+      int j;
+      xassert(code != NULL);
+      arg.list = create_arg_list(mpl);
+      /* parse <member list> */
+      for (j = 1; ; j++)
+      {  /* all member expressions must be n-tuples; so, if the current
+            expression is not n-tuple, convert it to 1-tuple */
+         if (code->type == A_NUMERIC)
+            code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
+         if (code->type == A_SYMBOLIC)
+            code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1);
+         /* now the expression must be n-tuple */
+         if (code->type != A_TUPLE)
+            error(mpl, "member expression has invalid type");
+         /* all member expressions must have identical dimension */
+         if (arg.list != NULL && arg.list->x->dim != code->dim)
+            error(mpl, "member %d has %d component%s while member %d ha"
+               "s %d component%s",
+               j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s",
+               j, code->dim, code->dim == 1 ? "" : "s");
+         /* append the current expression to the member list */
+         arg.list = expand_arg_list(mpl, arg.list, code);
+         /* check a token that follows the current expression */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RBRACE)
+            break;
+         else
+            error(mpl, "syntax error in literal set");
+         /* parse the next expression that follows the comma */
+         code = expression_5(mpl);
+      }
+      /* generate pseudo-code for <literal set> */
+      code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- indexing_expression - parse indexing expression.
+--
+-- This routine parses indexing expression using the syntax:
+--
+-- <indexing expression> ::= <literal set>
+-- <indexing expression> ::= { <indexing list> }
+-- <indexing expression> ::= { <indexing list> : <logical expression> }
+-- <indexing list> ::= <indexing element>
+-- <indexing list> ::= <indexing list> , <indexing element>
+-- <indexing element> ::= <basic expression>
+-- <indexing element> ::= <dummy index> in <basic expression>
+-- <indexing element> ::= <slice> in <basic expression>
+-- <dummy index> ::= <symbolic name>
+-- <slice> ::= ( <expression list> )
+-- <basic expression> ::= <expression 9>
+-- <logical expression> ::= <expression 13>
+--
+-- This routine creates domain for <indexing expression>, where each
+-- domain block corresponds to <indexing element>, and each domain slot
+-- corresponds to individual indexing position. */
+
+DOMAIN *indexing_expression(MPL *mpl)
+{     DOMAIN *domain;
+      DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      CODE *code;
+      xassert(mpl->token == T_LBRACE);
+      get_token(mpl /* { */);
+      if (mpl->token == T_RBRACE)
+         error(mpl, "empty indexing expression not allowed");
+      /* create domain to be constructed */
+      domain = create_domain(mpl);
+      /* parse either <member list> or <indexing list> that follows the
+         left brace */
+      for (;;)
+      {  /* domain block for <indexing element> is not created yet */
+         block = NULL;
+         /* pseudo-code for <basic expression> is not generated yet */
+         code = NULL;
+         /* check a token, which <indexing element> begins with */
+         if (mpl->token == T_NAME)
+         {  /* it is a symbolic name */
+            int next_token;
+            char *name;
+            /* symbolic name is recognized as dummy index only if it is
+               followed by the keyword 'in' and not declared */
+            get_token(mpl /* <symbolic name> */);
+            next_token = mpl->token;
+            unget_token(mpl);
+            if (!(next_token == T_IN &&
+                  avl_find_node(mpl->tree, mpl->image) == NULL))
+            {  /* this is not dummy index; the symbolic name begins an
+                  expression, which is either <basic expression> or the
+                  very first <member expression> in <literal set> */
+               goto expr;
+            }
+            /* create domain block with one slot, which is assigned the
+               dummy index */
+            block = create_block(mpl);
+            name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+            strcpy(name, mpl->image);
+            append_slot(mpl, block, name, NULL);
+            get_token(mpl /* <symbolic name> */);
+            /* the keyword 'in' is already checked above */
+            xassert(mpl->token == T_IN);
+            get_token(mpl /* in */);
+            /* <basic expression> that follows the keyword 'in' will be
+               parsed below */
+         }
+         else if (mpl->token == T_LEFT)
+         {  /* it is the left parenthesis; parse expression that begins
+               with this parenthesis (the flag is set in order to allow
+               recognizing slices; see the routine expression_list) */
+            mpl->flag_x = 1;
+            code = expression_9(mpl);
+            if (code->op != O_SLICE)
+            {  /* this is either <basic expression> or the very first
+                  <member expression> in <literal set> */
+               goto expr;
+            }
+            /* this is a slice; besides the corresponding domain block
+               is already created by expression_list() */
+            block = code->arg.slice;
+            code = NULL; /* <basic expression> is not parsed yet */
+            /* the keyword 'in' following the slice is already checked
+               by expression_list() */
+            xassert(mpl->token == T_IN);
+            get_token(mpl /* in */);
+            /* <basic expression> that follows the keyword 'in' will be
+               parsed below */
+         }
+expr:    /* parse expression that follows either the keyword 'in' (in
+            which case it can be <basic expression) or the left brace
+            (in which case it can be <basic expression> as well as the
+            very first <member expression> in <literal set>); note that
+            this expression can be already parsed above */
+         if (code == NULL) code = expression_9(mpl);
+         /* check the type of the expression just parsed */
+         if (code->type != A_ELEMSET)
+         {  /* it is not <basic expression> and therefore it can only
+               be the very first <member expression> in <literal set>;
+               however, then there must be no dummy index neither slice
+               between the left brace and this expression */
+            if (block != NULL)
+               error(mpl, "domain expression has invalid type");
+            /* parse the rest part of <literal set> and make this set
+               be <basic expression>, i.e. the construction {a, b, c}
+               is parsed as it were written as {A}, where A = {a, b, c}
+               is a temporary elemental set */
+            code = literal_set(mpl, code);
+         }
+         /* now pseudo-code for <basic set> has been built */
+         xassert(code != NULL);
+         xassert(code->type == A_ELEMSET);
+         xassert(code->dim > 0);
+         /* if domain block for the current <indexing element> is still
+            not created, create it for fake slice of the same dimension
+            as <basic set> */
+         if (block == NULL)
+         {  int j;
+            block = create_block(mpl);
+            for (j = 1; j <= code->dim; j++)
+               append_slot(mpl, block, NULL, NULL);
+         }
+         /* number of indexing positions in <indexing element> must be
+            the same as dimension of n-tuples in basic set */
+         {  int dim = 0;
+            for (slot = block->list; slot != NULL; slot = slot->next)
+               dim++;
+            if (dim != code->dim)
+               error(mpl,"%d %s specified for set of dimension %d",
+                  dim, dim == 1 ? "index" : "indices", code->dim);
+         }
+         /* store pseudo-code for <basic set> in the domain block */
+         xassert(block->code == NULL);
+         block->code = code;
+         /* and append the domain block to the domain */
+         append_block(mpl, domain, block);
+         /* the current <indexing element> has been completely parsed;
+            include all its dummy indices into the symbolic name table
+            to make them available for referencing from expressions;
+            implicit declarations of dummy indices remain valid while
+            the corresponding domain scope is valid */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         if (slot->name != NULL)
+         {  AVLNODE *node;
+            xassert(avl_find_node(mpl->tree, slot->name) == NULL);
+            node = avl_insert_node(mpl->tree, slot->name);
+            avl_set_node_type(node, A_INDEX);
+            avl_set_node_link(node, (void *)slot);
+         }
+         /* check a token that follows <indexing element> */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_COLON || mpl->token == T_RBRACE)
+            break;
+         else
+            error(mpl, "syntax error in indexing expression");
+      }
+      /* parse <logical expression> that follows the colon */
+      if (mpl->token == T_COLON)
+      {  get_token(mpl /* : */);
+         code = expression_13(mpl);
+         /* convert the expression to logical type, if necessary */
+         if (code->type == A_SYMBOLIC)
+            code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0);
+         if (code->type == A_NUMERIC)
+            code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0);
+         /* now the expression must be of logical type */
+         if (code->type != A_LOGICAL)
+            error(mpl, "expression following colon has invalid type");
+         xassert(code->dim == 0);
+         domain->code = code;
+         /* the right brace must follow the logical expression */
+         if (mpl->token != T_RBRACE)
+            error(mpl, "syntax error in indexing expression");
+      }
+      get_token(mpl /* } */);
+      return domain;
+}
+
+/*----------------------------------------------------------------------
+-- close_scope - close scope of indexing expression.
+--
+-- The routine closes the scope of indexing expression specified by its
+-- domain and thereby makes all dummy indices introduced in the indexing
+-- expression no longer available for referencing. */
+
+void close_scope(MPL *mpl, DOMAIN *domain)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      AVLNODE *node;
+      xassert(domain != NULL);
+      /* remove all dummy indices from the symbolic names table */
+      for (block = domain->list; block != NULL; block = block->next)
+      {  for (slot = block->list; slot != NULL; slot = slot->next)
+         {  if (slot->name != NULL)
+            {  node = avl_find_node(mpl->tree, slot->name);
+               xassert(node != NULL);
+               xassert(avl_get_node_type(node) == A_INDEX);
+               avl_delete_node(mpl->tree, node);
+            }
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- iterated_expression - parse iterated expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <iterated expression>
+-- <iterated expression> ::= sum <indexing expression> <expression 3>
+-- <iterated expression> ::= prod <indexing expression> <expression 3>
+-- <iterated expression> ::= min <indexing expression> <expression 3>
+-- <iterated expression> ::= max <indexing expression> <expression 3>
+-- <iterated expression> ::= exists <indexing expression>
+--                           <expression 12>
+-- <iterated expression> ::= forall <indexing expression>
+--                           <expression 12>
+-- <iterated expression> ::= setof <indexing expression> <expression 5>
+--
+-- Note that parsing "integrand" depends on the iterated operator. */
+
+#if 1 /* 07/IX-2008 */
+static void link_up(CODE *code)
+{     /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k],
+         where i and k are dummy indices defined out of the iterated
+         expression, we should link up pseudo-code for computing i+1
+         and k-1 to pseudo-code for computing the iterated expression;
+         this is needed to invalidate current value of the iterated
+         expression once i or k have been changed */
+      DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      for (block = code->arg.loop.domain->list; block != NULL;
+         block = block->next)
+      {  for (slot = block->list; slot != NULL; slot = slot->next)
+         {  if (slot->code != NULL)
+            {  xassert(slot->code->up == NULL);
+               slot->code->up = code;
+            }
+         }
+      }
+      return;
+}
+#endif
+
+CODE *iterated_expression(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      int op;
+      char opstr[8];
+      /* determine operation code */
+      xassert(mpl->token == T_NAME);
+      if (strcmp(mpl->image, "sum") == 0)
+         op = O_SUM;
+      else if (strcmp(mpl->image, "prod") == 0)
+         op = O_PROD;
+      else if (strcmp(mpl->image, "min") == 0)
+         op = O_MINIMUM;
+      else if (strcmp(mpl->image, "max") == 0)
+         op = O_MAXIMUM;
+      else if (strcmp(mpl->image, "forall") == 0)
+         op = O_FORALL;
+      else if (strcmp(mpl->image, "exists") == 0)
+         op = O_EXISTS;
+      else if (strcmp(mpl->image, "setof") == 0)
+         op = O_SETOF;
+      else
+         error(mpl, "operator %s unknown", mpl->image);
+      strcpy(opstr, mpl->image);
+      xassert(strlen(opstr) < sizeof(opstr));
+      get_token(mpl /* <symbolic name> */);
+      /* check the left brace that follows the operator name */
+      xassert(mpl->token == T_LBRACE);
+      /* parse indexing expression that controls iterating */
+      arg.loop.domain = indexing_expression(mpl);
+      /* parse "integrand" expression and generate pseudo-code */
+      switch (op)
+      {  case O_SUM:
+         case O_PROD:
+         case O_MINIMUM:
+         case O_MAXIMUM:
+            arg.loop.x = expression_3(mpl);
+            /* convert the integrand to numeric type, if necessary */
+            if (arg.loop.x->type == A_SYMBOLIC)
+               arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
+                  A_NUMERIC, 0);
+            /* now the integrand must be of numeric type or linear form
+               (the latter is only allowed for the sum operator) */
+            if (!(arg.loop.x->type == A_NUMERIC ||
+                  op == O_SUM && arg.loop.x->type == A_FORMULA))
+err:           error(mpl, "integrand following %s{...} has invalid type"
+                  , opstr);
+            xassert(arg.loop.x->dim == 0);
+            /* generate pseudo-code */
+            code = make_code(mpl, op, &arg, arg.loop.x->type, 0);
+            break;
+         case O_FORALL:
+         case O_EXISTS:
+            arg.loop.x = expression_12(mpl);
+            /* convert the integrand to logical type, if necessary */
+            if (arg.loop.x->type == A_SYMBOLIC)
+               arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
+                  A_NUMERIC, 0);
+            if (arg.loop.x->type == A_NUMERIC)
+               arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x,
+                  A_LOGICAL, 0);
+            /* now the integrand must be of logical type */
+            if (arg.loop.x->type != A_LOGICAL) goto err;
+            xassert(arg.loop.x->dim == 0);
+            /* generate pseudo-code */
+            code = make_code(mpl, op, &arg, A_LOGICAL, 0);
+            break;
+         case O_SETOF:
+            arg.loop.x = expression_5(mpl);
+            /* convert the integrand to 1-tuple, if necessary */
+            if (arg.loop.x->type == A_NUMERIC)
+               arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x,
+                  A_SYMBOLIC, 0);
+            if (arg.loop.x->type == A_SYMBOLIC)
+               arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x,
+                  A_TUPLE, 1);
+            /* now the integrand must be n-tuple */
+            if (arg.loop.x->type != A_TUPLE) goto err;
+            xassert(arg.loop.x->dim > 0);
+            /* generate pseudo-code */
+            code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim);
+            break;
+         default:
+            xassert(op != op);
+      }
+      /* close the scope of the indexing expression */
+      close_scope(mpl, arg.loop.domain);
+#if 1 /* 07/IX-2008 */
+      link_up(code);
+#endif
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- domain_arity - determine arity of domain.
+--
+-- This routine returns arity of specified domain, which is number of
+-- its free dummy indices. */
+
+int domain_arity(MPL *mpl, DOMAIN *domain)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      int arity;
+      xassert(mpl == mpl);
+      arity = 0;
+      for (block = domain->list; block != NULL; block = block->next)
+         for (slot = block->list; slot != NULL; slot = slot->next)
+            if (slot->code == NULL) arity++;
+      return arity;
+}
+
+/*----------------------------------------------------------------------
+-- set_expression - parse set expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= { }
+-- <primary expression> ::= <indexing expression> */
+
+CODE *set_expression(MPL *mpl)
+{     CODE *code;
+      OPERANDS arg;
+      xassert(mpl->token == T_LBRACE);
+      get_token(mpl /* { */);
+      /* check a token that follows the left brace */
+      if (mpl->token == T_RBRACE)
+      {  /* it is the right brace, so the resultant is an empty set of
+            dimension 1 */
+         arg.list = NULL;
+         /* generate pseudo-code to build the resultant set */
+         code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1);
+         get_token(mpl /* } */);
+      }
+      else
+      {  /* the next token begins an indexing expression */
+         unget_token(mpl);
+         arg.loop.domain = indexing_expression(mpl);
+         arg.loop.x = NULL; /* integrand is not used */
+         /* close the scope of the indexing expression */
+         close_scope(mpl, arg.loop.domain);
+         /* generate pseudo-code to build the resultant set */
+         code = make_code(mpl, O_BUILD, &arg, A_ELEMSET,
+            domain_arity(mpl, arg.loop.domain));
+#if 1 /* 07/IX-2008 */
+         link_up(code);
+#endif
+      }
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- branched_expression - parse conditional expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <branched expression>
+-- <branched expression> ::= if <logical expression> then <expression 9>
+-- <branched expression> ::= if <logical expression> then <expression 9>
+--                           else <expression 9>
+-- <logical expression> ::= <expression 13> */
+
+CODE *branched_expression(MPL *mpl)
+{     CODE *code, *x, *y, *z;
+      xassert(mpl->token == T_IF);
+      get_token(mpl /* if */);
+      /* parse <logical expression> that follows 'if' */
+      x = expression_13(mpl);
+      /* convert the expression to logical type, if necessary */
+      if (x->type == A_SYMBOLIC)
+         x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+      if (x->type == A_NUMERIC)
+         x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+      /* now the expression must be of logical type */
+      if (x->type != A_LOGICAL)
+         error(mpl, "expression following if has invalid type");
+      xassert(x->dim == 0);
+      /* the keyword 'then' must follow the logical expression */
+      if (mpl->token != T_THEN)
+         error(mpl, "keyword then missing where expected");
+      get_token(mpl /* then */);
+      /* parse <expression> that follows 'then' and check its type */
+      y = expression_9(mpl);
+      if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC ||
+            y->type == A_ELEMSET || y->type == A_FORMULA))
+         error(mpl, "expression following then has invalid type");
+      /* if the expression that follows the keyword 'then' is elemental
+         set, the keyword 'else' cannot be omitted; otherwise else-part
+         is optional */
+      if (mpl->token != T_ELSE)
+      {  if (y->type == A_ELEMSET)
+            error(mpl, "keyword else missing where expected");
+         z = NULL;
+         goto skip;
+      }
+      get_token(mpl /* else */);
+      /* parse <expression> that follow 'else' and check its type */
+      z = expression_9(mpl);
+      if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC ||
+            z->type == A_ELEMSET || z->type == A_FORMULA))
+         error(mpl, "expression following else has invalid type");
+      /* convert to identical types, if necessary */
+      if (y->type == A_FORMULA || z->type == A_FORMULA)
+      {  if (y->type == A_SYMBOLIC)
+            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+         if (y->type == A_NUMERIC)
+            y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+         if (z->type == A_SYMBOLIC)
+            z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
+         if (z->type == A_NUMERIC)
+            z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0);
+      }
+      if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC)
+      {  if (y->type == A_NUMERIC)
+            y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+         if (z->type == A_NUMERIC)
+            z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0);
+      }
+      /* now both expressions must have identical types */
+      if (y->type != z->type)
+         error(mpl, "expressions following then and else have incompati"
+            "ble types");
+      /* and identical dimensions */
+      if (y->dim != z->dim)
+         error(mpl, "expressions following then and else have different"
+            " dimensions %d and %d, respectively", y->dim, z->dim);
+skip: /* generate pseudo-code to perform branching */
+      code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- primary_expression - parse primary expression.
+--
+-- This routine parses primary expression using the syntax:
+--
+-- <primary expression> ::= <numeric literal>
+-- <primary expression> ::= Infinity
+-- <primary expression> ::= <string literal>
+-- <primary expression> ::= <dummy index>
+-- <primary expression> ::= <set name>
+-- <primary expression> ::= <set name> [ <subscript list> ]
+-- <primary expression> ::= <parameter name>
+-- <primary expression> ::= <parameter name> [ <subscript list> ]
+-- <primary expression> ::= <variable name>
+-- <primary expression> ::= <variable name> [ <subscript list> ]
+-- <primary expression> ::= <built-in function> ( <argument list> )
+-- <primary expression> ::= ( <expression list> )
+-- <primary expression> ::= <iterated expression>
+-- <primary expression> ::= { }
+-- <primary expression> ::= <indexing expression>
+-- <primary expression> ::= <branched expression>
+--
+-- For complete list of syntactic rules for <primary expression> see
+-- comments to the corresponding parsing routines. */
+
+CODE *primary_expression(MPL *mpl)
+{     CODE *code;
+      if (mpl->token == T_NUMBER)
+      {  /* parse numeric literal */
+         code = numeric_literal(mpl);
+      }
+#if 1 /* 21/VII-2006 */
+      else if (mpl->token == T_INFINITY)
+      {  /* parse "infinity" */
+         OPERANDS arg;
+         arg.num = DBL_MAX;
+         code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
+         get_token(mpl /* Infinity */);
+      }
+#endif
+      else if (mpl->token == T_STRING)
+      {  /* parse string literal */
+         code = string_literal(mpl);
+      }
+      else if (mpl->token == T_NAME)
+      {  int next_token;
+         get_token(mpl /* <symbolic name> */);
+         next_token = mpl->token;
+         unget_token(mpl);
+         /* check a token that follows <symbolic name> */
+         switch (next_token)
+         {  case T_LBRACKET:
+               /* parse reference to subscripted object */
+               code = object_reference(mpl);
+               break;
+            case T_LEFT:
+               /* parse reference to built-in function */
+               code = function_reference(mpl);
+               break;
+            case T_LBRACE:
+               /* parse iterated expression */
+               code = iterated_expression(mpl);
+               break;
+            default:
+               /* parse reference to unsubscripted object */
+               code = object_reference(mpl);
+               break;
+         }
+      }
+      else if (mpl->token == T_LEFT)
+      {  /* parse parenthesized expression */
+         code = expression_list(mpl);
+      }
+      else if (mpl->token == T_LBRACE)
+      {  /* parse set expression */
+         code = set_expression(mpl);
+      }
+      else if (mpl->token == T_IF)
+      {  /* parse conditional expression */
+         code = branched_expression(mpl);
+      }
+      else if (is_reserved(mpl))
+      {  /* other reserved keywords cannot be used here */
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      }
+      else
+         error(mpl, "syntax error in expression");
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- error_preceding - raise error if preceding operand has wrong type.
+--
+-- This routine is called to raise error if operand that precedes some
+-- infix operator has invalid type. */
+
+void error_preceding(MPL *mpl, char *opstr)
+{     error(mpl, "operand preceding %s has invalid type", opstr);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- error_following - raise error if following operand has wrong type.
+--
+-- This routine is called to raise error if operand that follows some
+-- infix operator has invalid type. */
+
+void error_following(MPL *mpl, char *opstr)
+{     error(mpl, "operand following %s has invalid type", opstr);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- error_dimension - raise error if operands have different dimension.
+--
+-- This routine is called to raise error if two operands of some infix
+-- operator have different dimension. */
+
+void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2)
+{     error(mpl, "operands preceding and following %s have different di"
+         "mensions %d and %d, respectively", opstr, dim1, dim2);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- expression_0 - parse expression of level 0.
+--
+-- This routine parses expression of level 0 using the syntax:
+--
+-- <expression 0> ::= <primary expression> */
+
+CODE *expression_0(MPL *mpl)
+{     CODE *code;
+      code = primary_expression(mpl);
+      return code;
+}
+
+/*----------------------------------------------------------------------
+-- expression_1 - parse expression of level 1.
+--
+-- This routine parses expression of level 1 using the syntax:
+--
+-- <expression 1> ::= <expression 0>
+-- <expression 1> ::= <expression 0> <power> <expression 1>
+-- <expression 1> ::= <expression 0> <power> <expression 2>
+-- <power> ::= ^ | ** */
+
+CODE *expression_1(MPL *mpl)
+{     CODE *x, *y;
+      char opstr[8];
+      x = expression_0(mpl);
+      if (mpl->token == T_POWER)
+      {  strcpy(opstr, mpl->image);
+         xassert(strlen(opstr) < sizeof(opstr));
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (x->type != A_NUMERIC)
+            error_preceding(mpl, opstr);
+         get_token(mpl /* ^ | ** */);
+         if (mpl->token == T_PLUS || mpl->token == T_MINUS)
+            y = expression_2(mpl);
+         else
+            y = expression_1(mpl);
+         if (y->type == A_SYMBOLIC)
+            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+         if (y->type != A_NUMERIC)
+            error_following(mpl, opstr);
+         x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0);
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_2 - parse expression of level 2.
+--
+-- This routine parses expression of level 2 using the syntax:
+--
+-- <expression 2> ::= <expression 1>
+-- <expression 2> ::= + <expression 1>
+-- <expression 2> ::= - <expression 1> */
+
+CODE *expression_2(MPL *mpl)
+{     CODE *x;
+      if (mpl->token == T_PLUS)
+      {  get_token(mpl /* + */);
+         x = expression_1(mpl);
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+            error_following(mpl, "+");
+         x = make_unary(mpl, O_PLUS, x, x->type, 0);
+      }
+      else if (mpl->token == T_MINUS)
+      {  get_token(mpl /* - */);
+         x = expression_1(mpl);
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+            error_following(mpl, "-");
+         x = make_unary(mpl, O_MINUS, x, x->type, 0);
+      }
+      else
+         x = expression_1(mpl);
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_3 - parse expression of level 3.
+--
+-- This routine parses expression of level 3 using the syntax:
+--
+-- <expression 3> ::= <expression 2>
+-- <expression 3> ::= <expression 3> * <expression 2>
+-- <expression 3> ::= <expression 3> / <expression 2>
+-- <expression 3> ::= <expression 3> div <expression 2>
+-- <expression 3> ::= <expression 3> mod <expression 2> */
+
+CODE *expression_3(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_2(mpl);
+      for (;;)
+      {  if (mpl->token == T_ASTERISK)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "*");
+            get_token(mpl /* * */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+               error_following(mpl, "*");
+            if (x->type == A_FORMULA && y->type == A_FORMULA)
+               error(mpl, "multiplication of linear forms not allowed");
+            if (x->type == A_NUMERIC && y->type == A_NUMERIC)
+               x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0);
+            else
+               x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0);
+         }
+         else if (mpl->token == T_SLASH)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "/");
+            get_token(mpl /* / */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "/");
+            if (x->type == A_NUMERIC)
+               x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0);
+            else
+               x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0);
+         }
+         else if (mpl->token == T_DIV)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, "div");
+            get_token(mpl /* div */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "div");
+            x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0);
+         }
+         else if (mpl->token == T_MOD)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, "mod");
+            get_token(mpl /* mod */);
+            y = expression_2(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "mod");
+            x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_4 - parse expression of level 4.
+--
+-- This routine parses expression of level 4 using the syntax:
+--
+-- <expression 4> ::= <expression 3>
+-- <expression 4> ::= <expression 4> + <expression 3>
+-- <expression 4> ::= <expression 4> - <expression 3>
+-- <expression 4> ::= <expression 4> less <expression 3> */
+
+CODE *expression_4(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_3(mpl);
+      for (;;)
+      {  if (mpl->token == T_PLUS)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "+");
+            get_token(mpl /* + */);
+            y = expression_3(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+               error_following(mpl, "+");
+            if (x->type == A_NUMERIC && y->type == A_FORMULA)
+               x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
+            if (x->type == A_FORMULA && y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+            x = make_binary(mpl, O_ADD, x, y, x->type, 0);
+         }
+         else if (mpl->token == T_MINUS)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
+               error_preceding(mpl, "-");
+            get_token(mpl /* - */);
+            y = expression_3(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
+               error_following(mpl, "-");
+            if (x->type == A_NUMERIC && y->type == A_FORMULA)
+               x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
+            if (x->type == A_FORMULA && y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
+            x = make_binary(mpl, O_SUB, x, y, x->type, 0);
+         }
+         else if (mpl->token == T_LESS)
+         {  if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, "less");
+            get_token(mpl /* less */);
+            y = expression_3(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, "less");
+            x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_5 - parse expression of level 5.
+--
+-- This routine parses expression of level 5 using the syntax:
+--
+-- <expression 5> ::= <expression 4>
+-- <expression 5> ::= <expression 5> & <expression 4> */
+
+CODE *expression_5(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_4(mpl);
+      for (;;)
+      {  if (mpl->token == T_CONCAT)
+         {  if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+            if (x->type != A_SYMBOLIC)
+               error_preceding(mpl, "&");
+            get_token(mpl /* & */);
+            y = expression_4(mpl);
+            if (y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+            if (y->type != A_SYMBOLIC)
+               error_following(mpl, "&");
+            x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_6 - parse expression of level 6.
+--
+-- This routine parses expression of level 6 using the syntax:
+--
+-- <expression 6> ::= <expression 5>
+-- <expression 6> ::= <expression 5> .. <expression 5>
+-- <expression 6> ::= <expression 5> .. <expression 5> by
+--                    <expression 5> */
+
+CODE *expression_6(MPL *mpl)
+{     CODE *x, *y, *z;
+      x = expression_5(mpl);
+      if (mpl->token == T_DOTS)
+      {  if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (x->type != A_NUMERIC)
+            error_preceding(mpl, "..");
+         get_token(mpl /* .. */);
+         y = expression_5(mpl);
+         if (y->type == A_SYMBOLIC)
+            y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+         if (y->type != A_NUMERIC)
+            error_following(mpl, "..");
+         if (mpl->token == T_BY)
+         {  get_token(mpl /* by */);
+            z = expression_5(mpl);
+            if (z->type == A_SYMBOLIC)
+               z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
+            if (z->type != A_NUMERIC)
+               error_following(mpl, "by");
+         }
+         else
+            z = NULL;
+         x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1);
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_7 - parse expression of level 7.
+--
+-- This routine parses expression of level 7 using the syntax:
+--
+-- <expression 7> ::= <expression 6>
+-- <expression 7> ::= <expression 7> cross <expression 6> */
+
+CODE *expression_7(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_6(mpl);
+      for (;;)
+      {  if (mpl->token == T_CROSS)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "cross");
+            get_token(mpl /* cross */);
+            y = expression_6(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "cross");
+            x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET,
+               x->dim + y->dim);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_8 - parse expression of level 8.
+--
+-- This routine parses expression of level 8 using the syntax:
+--
+-- <expression 8> ::= <expression 7>
+-- <expression 8> ::= <expression 8> inter <expression 7> */
+
+CODE *expression_8(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_7(mpl);
+      for (;;)
+      {  if (mpl->token == T_INTER)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "inter");
+            get_token(mpl /* inter */);
+            y = expression_7(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "inter");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "inter", x->dim, y->dim);
+            x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_9 - parse expression of level 9.
+--
+-- This routine parses expression of level 9 using the syntax:
+--
+-- <expression 9> ::= <expression 8>
+-- <expression 9> ::= <expression 9> union <expression 8>
+-- <expression 9> ::= <expression 9> diff <expression 8>
+-- <expression 9> ::= <expression 9> symdiff <expression 8> */
+
+CODE *expression_9(MPL *mpl)
+{     CODE *x, *y;
+      x = expression_8(mpl);
+      for (;;)
+      {  if (mpl->token == T_UNION)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "union");
+            get_token(mpl /* union */);
+            y = expression_8(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "union");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "union", x->dim, y->dim);
+            x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim);
+         }
+         else if (mpl->token == T_DIFF)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "diff");
+            get_token(mpl /* diff */);
+            y = expression_8(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "diff");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "diff", x->dim, y->dim);
+            x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim);
+         }
+         else if (mpl->token == T_SYMDIFF)
+         {  if (x->type != A_ELEMSET)
+               error_preceding(mpl, "symdiff");
+            get_token(mpl /* symdiff */);
+            y = expression_8(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, "symdiff");
+            if (x->dim != y->dim)
+               error_dimension(mpl, "symdiff", x->dim, y->dim);
+            x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_10 - parse expression of level 10.
+--
+-- This routine parses expression of level 10 using the syntax:
+--
+-- <expression 10> ::= <expression 9>
+-- <expression 10> ::= <expression 9> <rho> <expression 9>
+-- <rho> ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in |
+--           within | not within | ! within */
+
+CODE *expression_10(MPL *mpl)
+{     CODE *x, *y;
+      int op = -1;
+      char opstr[16];
+      x = expression_9(mpl);
+      strcpy(opstr, "");
+      switch (mpl->token)
+      {  case T_LT:
+            op = O_LT; break;
+         case T_LE:
+            op = O_LE; break;
+         case T_EQ:
+            op = O_EQ; break;
+         case T_GE:
+            op = O_GE; break;
+         case T_GT:
+            op = O_GT; break;
+         case T_NE:
+            op = O_NE; break;
+         case T_IN:
+            op = O_IN; break;
+         case T_WITHIN:
+            op = O_WITHIN; break;
+         case T_NOT:
+            strcpy(opstr, mpl->image);
+            get_token(mpl /* not | ! */);
+            if (mpl->token == T_IN)
+               op = O_NOTIN;
+            else if (mpl->token == T_WITHIN)
+               op = O_NOTWITHIN;
+            else
+               error(mpl, "invalid use of %s", opstr);
+            strcat(opstr, " ");
+            break;
+         default:
+            goto done;
+      }
+      strcat(opstr, mpl->image);
+      xassert(strlen(opstr) < sizeof(opstr));
+      switch (op)
+      {  case O_EQ:
+         case O_NE:
+#if 1 /* 02/VIII-2008 */
+         case O_LT:
+         case O_LE:
+         case O_GT:
+         case O_GE:
+#endif
+            if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC))
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC))
+               error_following(mpl, opstr);
+            if (x->type == A_NUMERIC && y->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+            if (x->type == A_SYMBOLIC && y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+#if 0 /* 02/VIII-2008 */
+         case O_LT:
+         case O_LE:
+         case O_GT:
+         case O_GE:
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type != A_NUMERIC)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type != A_NUMERIC)
+               error_following(mpl, opstr);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+#endif
+         case O_IN:
+         case O_NOTIN:
+            if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1);
+            if (x->type != A_TUPLE)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, opstr);
+            if (x->dim != y->dim)
+               error_dimension(mpl, opstr, x->dim, y->dim);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+         case O_WITHIN:
+         case O_NOTWITHIN:
+            if (x->type != A_ELEMSET)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* <rho> */);
+            y = expression_9(mpl);
+            if (y->type != A_ELEMSET)
+               error_following(mpl, opstr);
+            if (x->dim != y->dim)
+               error_dimension(mpl, opstr, x->dim, y->dim);
+            x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
+            break;
+         default:
+            xassert(op != op);
+      }
+done: return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_11 - parse expression of level 11.
+--
+-- This routine parses expression of level 11 using the syntax:
+--
+-- <expression 11> ::= <expression 10>
+-- <expression 11> ::= not <expression 10>
+-- <expression 11> ::= ! <expression 10> */
+
+CODE *expression_11(MPL *mpl)
+{     CODE *x;
+      char opstr[8];
+      if (mpl->token == T_NOT)
+      {  strcpy(opstr, mpl->image);
+         xassert(strlen(opstr) < sizeof(opstr));
+         get_token(mpl /* not | ! */);
+         x = expression_10(mpl);
+         if (x->type == A_SYMBOLIC)
+            x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+         if (x->type == A_NUMERIC)
+            x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+         if (x->type != A_LOGICAL)
+            error_following(mpl, opstr);
+         x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0);
+      }
+      else
+         x = expression_10(mpl);
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_12 - parse expression of level 12.
+--
+-- This routine parses expression of level 12 using the syntax:
+--
+-- <expression 12> ::= <expression 11>
+-- <expression 12> ::= <expression 12> and <expression 11>
+-- <expression 12> ::= <expression 12> && <expression 11> */
+
+CODE *expression_12(MPL *mpl)
+{     CODE *x, *y;
+      char opstr[8];
+      x = expression_11(mpl);
+      for (;;)
+      {  if (mpl->token == T_AND)
+         {  strcpy(opstr, mpl->image);
+            xassert(strlen(opstr) < sizeof(opstr));
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+            if (x->type != A_LOGICAL)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* and | && */);
+            y = expression_11(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
+            if (y->type != A_LOGICAL)
+               error_following(mpl, opstr);
+            x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- expression_13 - parse expression of level 13.
+--
+-- This routine parses expression of level 13 using the syntax:
+--
+-- <expression 13> ::= <expression 12>
+-- <expression 13> ::= <expression 13> or <expression 12>
+-- <expression 13> ::= <expression 13> || <expression 12> */
+
+CODE *expression_13(MPL *mpl)
+{     CODE *x, *y;
+      char opstr[8];
+      x = expression_12(mpl);
+      for (;;)
+      {  if (mpl->token == T_OR)
+         {  strcpy(opstr, mpl->image);
+            xassert(strlen(opstr) < sizeof(opstr));
+            if (x->type == A_SYMBOLIC)
+               x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
+            if (x->type == A_NUMERIC)
+               x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
+            if (x->type != A_LOGICAL)
+               error_preceding(mpl, opstr);
+            get_token(mpl /* or | || */);
+            y = expression_12(mpl);
+            if (y->type == A_SYMBOLIC)
+               y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
+            if (y->type == A_NUMERIC)
+               y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
+            if (y->type != A_LOGICAL)
+               error_following(mpl, opstr);
+            x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0);
+         }
+         else
+            break;
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- set_statement - parse set statement.
+--
+-- This routine parses set statement using the syntax:
+--
+-- <set statement> ::= set <symbolic name> <alias> <domain>
+--                     <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , dimen <numeric literal>
+-- <attributes> ::= <attributes> , within <expression 9>
+-- <attributes> ::= <attributes> , := <expression 9>
+-- <attributes> ::= <attributes> , default <expression 9>
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+SET *set_statement(MPL *mpl)
+{     SET *set;
+      int dimen_used = 0;
+      xassert(is_keyword(mpl, "set"));
+      get_token(mpl /* set */);
+      /* symbolic name must follow the keyword 'set' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model set */
+      set = alloc(SET);
+      set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(set->name, mpl->image);
+      set->alias = NULL;
+      set->dim = 0;
+      set->domain = NULL;
+      set->dimen = 0;
+      set->within = NULL;
+      set->assign = NULL;
+      set->option = NULL;
+      set->gadget = NULL;
+      set->data = 0;
+      set->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(set->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  set->domain = indexing_expression(mpl);
+         set->dim = domain_arity(mpl, set->domain);
+      }
+      /* include the set name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, set->name);
+         avl_set_node_type(node, A_SET);
+         avl_set_node_link(node, (void *)set);
+      }
+      /* parse the list of optional attributes */
+      for (;;)
+      {  if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         if (is_keyword(mpl, "dimen"))
+         {  /* dimension of set members */
+            int dimen;
+            get_token(mpl /* dimen */);
+            if (!(mpl->token == T_NUMBER &&
+                  1.0 <= mpl->value && mpl->value <= 20.0 &&
+                  floor(mpl->value) == mpl->value))
+               error(mpl, "dimension must be integer between 1 and 20");
+            dimen = (int)(mpl->value + 0.5);
+            if (dimen_used)
+               error(mpl, "at most one dimension attribute allowed");
+            if (set->dimen > 0)
+               error(mpl, "dimension %d conflicts with dimension %d alr"
+                  "eady determined", dimen, set->dimen);
+            set->dimen = dimen;
+            dimen_used = 1;
+            get_token(mpl /* <numeric literal> */);
+         }
+         else if (mpl->token == T_WITHIN || mpl->token == T_IN)
+         {  /* restricting superset */
+            WITHIN *within, *temp;
+            if (mpl->token == T_IN && !mpl->as_within)
+            {  warning(mpl, "keyword in understood as within");
+               mpl->as_within = 1;
+            }
+            get_token(mpl /* within */);
+            /* create new restricting superset list entry and append it
+               to the within-list */
+            within = alloc(WITHIN);
+            within->code = NULL;
+            within->next = NULL;
+            if (set->within == NULL)
+               set->within = within;
+            else
+            {  for (temp = set->within; temp->next != NULL; temp =
+                  temp->next);
+               temp->next = within;
+            }
+            /* parse an expression that follows 'within' */
+            within->code = expression_9(mpl);
+            if (within->code->type != A_ELEMSET)
+               error(mpl, "expression following within has invalid type"
+                  );
+            xassert(within->code->dim > 0);
+            /* check/set dimension of set members */
+            if (set->dimen == 0) set->dimen = within->code->dim;
+            if (set->dimen != within->code->dim)
+               error(mpl, "set expression following within must have di"
+                  "mension %d rather than %d",
+                  set->dimen, within->code->dim);
+         }
+         else if (mpl->token == T_ASSIGN)
+         {  /* assignment expression */
+            if (!(set->assign == NULL && set->option == NULL &&
+                  set->gadget == NULL))
+err:           error(mpl, "at most one := or default/data allowed");
+            get_token(mpl /* := */);
+            /* parse an expression that follows ':=' */
+            set->assign = expression_9(mpl);
+            if (set->assign->type != A_ELEMSET)
+               error(mpl, "expression following := has invalid type");
+            xassert(set->assign->dim > 0);
+            /* check/set dimension of set members */
+            if (set->dimen == 0) set->dimen = set->assign->dim;
+            if (set->dimen != set->assign->dim)
+               error(mpl, "set expression following := must have dimens"
+                  "ion %d rather than %d",
+                  set->dimen, set->assign->dim);
+         }
+         else if (is_keyword(mpl, "default"))
+         {  /* expression for default value */
+            if (!(set->assign == NULL && set->option == NULL)) goto err;
+            get_token(mpl /* := */);
+            /* parse an expression that follows 'default' */
+            set->option = expression_9(mpl);
+            if (set->option->type != A_ELEMSET)
+               error(mpl, "expression following default has invalid typ"
+                  "e");
+            xassert(set->option->dim > 0);
+            /* check/set dimension of set members */
+            if (set->dimen == 0) set->dimen = set->option->dim;
+            if (set->dimen != set->option->dim)
+               error(mpl, "set expression following default must have d"
+                  "imension %d rather than %d",
+                  set->dimen, set->option->dim);
+         }
+#if 1 /* 12/XII-2008 */
+         else if (is_keyword(mpl, "data"))
+         {  /* gadget to initialize the set by data from plain set */
+            GADGET *gadget;
+            AVLNODE *node;
+            int i, k, fff[20];
+            if (!(set->assign == NULL && set->gadget == NULL)) goto err;
+            get_token(mpl /* data */);
+            set->gadget = gadget = alloc(GADGET);
+            /* set name must follow the keyword 'data' */
+            if (mpl->token == T_NAME)
+               ;
+            else if (is_reserved(mpl))
+               error(mpl, "invalid use of reserved keyword %s",
+                  mpl->image);
+            else
+               error(mpl, "set name missing where expected");
+            /* find the set in the symbolic name table */
+            node = avl_find_node(mpl->tree, mpl->image);
+            if (node == NULL)
+               error(mpl, "%s not defined", mpl->image);
+            if (avl_get_node_type(node) != A_SET)
+err1:          error(mpl, "%s not a plain set", mpl->image);
+            gadget->set = avl_get_node_link(node);
+            if (gadget->set->dim != 0) goto err1;
+            if (gadget->set == set)
+               error(mpl, "set cannot be initialized by itself");
+            /* check and set dimensions */
+            if (set->dim >= gadget->set->dimen)
+err2:          error(mpl, "dimension of %s too small", mpl->image);
+            if (set->dimen == 0)
+               set->dimen = gadget->set->dimen - set->dim;
+            if (set->dim + set->dimen > gadget->set->dimen)
+               goto err2;
+            else if (set->dim + set->dimen < gadget->set->dimen)
+               error(mpl, "dimension of %s too big", mpl->image);
+            get_token(mpl /* set name */);
+            /* left parenthesis must follow the set name */
+            if (mpl->token == T_LEFT)
+               get_token(mpl /* ( */);
+            else
+               error(mpl, "left parenthesis missing where expected");
+            /* parse permutation of component numbers */
+            for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0;
+            k = 0;
+            for (;;)
+            {  if (mpl->token != T_NUMBER)
+                  error(mpl, "component number missing where expected");
+               if (str2int(mpl->image, &i) != 0)
+err3:             error(mpl, "component number must be integer between "
+                     "1 and %d", gadget->set->dimen);
+               if (!(1 <= i && i <= gadget->set->dimen)) goto err3;
+               if (fff[i-1] != 0)
+                  error(mpl, "component %d multiply specified", i);
+               gadget->ind[k++] = i, fff[i-1] = 1;
+               xassert(k <= gadget->set->dimen);
+               get_token(mpl /* number */);
+               if (mpl->token == T_COMMA)
+                  get_token(mpl /* , */);
+               else if (mpl->token == T_RIGHT)
+                  break;
+               else
+                  error(mpl, "syntax error in data attribute");
+            }
+            if (k < gadget->set->dimen)
+               error(mpl, "there are must be %d components rather than "
+                  "%d", gadget->set->dimen, k);
+            get_token(mpl /* ) */);
+         }
+#endif
+         else
+            error(mpl, "syntax error in set statement");
+      }
+      /* close the domain scope */
+      if (set->domain != NULL) close_scope(mpl, set->domain);
+      /* if dimension of set members is still unknown, set it to 1 */
+      if (set->dimen == 0) set->dimen = 1;
+      /* the set statement has been completely parsed */
+      xassert(mpl->token == T_SEMICOLON);
+      get_token(mpl /* ; */);
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- parameter_statement - parse parameter statement.
+--
+-- This routine parses parameter statement using the syntax:
+--
+-- <parameter statement> ::= param <symbolic name> <alias> <domain>
+--                           <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , integer
+-- <attributes> ::= <attributes> , binary
+-- <attributes> ::= <attributes> , symbolic
+-- <attributes> ::= <attributes> , <rho> <expression 5>
+-- <attributes> ::= <attributes> , in <expression 9>
+-- <attributes> ::= <attributes> , := <expression 5>
+-- <attributes> ::= <attributes> , default <expression 5>
+-- <rho> ::= < | <= | = | == | >= | > | <> | !=
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+PARAMETER *parameter_statement(MPL *mpl)
+{     PARAMETER *par;
+      int integer_used = 0, binary_used = 0, symbolic_used = 0;
+      xassert(is_keyword(mpl, "param"));
+      get_token(mpl /* param */);
+      /* symbolic name must follow the keyword 'param' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model parameter */
+      par = alloc(PARAMETER);
+      par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(par->name, mpl->image);
+      par->alias = NULL;
+      par->dim = 0;
+      par->domain = NULL;
+      par->type = A_NUMERIC;
+      par->cond = NULL;
+      par->in = NULL;
+      par->assign = NULL;
+      par->option = NULL;
+      par->data = 0;
+      par->defval = NULL;
+      par->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(par->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  par->domain = indexing_expression(mpl);
+         par->dim = domain_arity(mpl, par->domain);
+      }
+      /* include the parameter name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, par->name);
+         avl_set_node_type(node, A_PARAMETER);
+         avl_set_node_link(node, (void *)par);
+      }
+      /* parse the list of optional attributes */
+      for (;;)
+      {  if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         if (is_keyword(mpl, "integer"))
+         {  if (integer_used)
+               error(mpl, "at most one integer allowed");
+            if (par->type == A_SYMBOLIC)
+               error(mpl, "symbolic parameter cannot be integer");
+            if (par->type != A_BINARY) par->type = A_INTEGER;
+            integer_used = 1;
+            get_token(mpl /* integer */);
+         }
+         else if (is_keyword(mpl, "binary"))
+bin:     {  if (binary_used)
+               error(mpl, "at most one binary allowed");
+            if (par->type == A_SYMBOLIC)
+               error(mpl, "symbolic parameter cannot be binary");
+            par->type = A_BINARY;
+            binary_used = 1;
+            get_token(mpl /* binary */);
+         }
+         else if (is_keyword(mpl, "logical"))
+         {  if (!mpl->as_binary)
+            {  warning(mpl, "keyword logical understood as binary");
+               mpl->as_binary = 1;
+            }
+            goto bin;
+         }
+         else if (is_keyword(mpl, "symbolic"))
+         {  if (symbolic_used)
+               error(mpl, "at most one symbolic allowed");
+            if (par->type != A_NUMERIC)
+               error(mpl, "integer or binary parameter cannot be symbol"
+                  "ic");
+            /* the parameter may be referenced from expressions given
+               in the same parameter declaration, so its type must be
+               completed before parsing that expressions */
+            if (!(par->cond == NULL && par->in == NULL &&
+                  par->assign == NULL && par->option == NULL))
+               error(mpl, "keyword symbolic must precede any other para"
+                  "meter attributes");
+            par->type = A_SYMBOLIC;
+            symbolic_used = 1;
+            get_token(mpl /* symbolic */);
+         }
+         else if (mpl->token == T_LT || mpl->token == T_LE ||
+                  mpl->token == T_EQ || mpl->token == T_GE ||
+                  mpl->token == T_GT || mpl->token == T_NE)
+         {  /* restricting condition */
+            CONDITION *cond, *temp;
+            char opstr[8];
+            /* create new restricting condition list entry and append
+               it to the conditions list */
+            cond = alloc(CONDITION);
+            switch (mpl->token)
+            {  case T_LT:
+                  cond->rho = O_LT, strcpy(opstr, mpl->image); break;
+               case T_LE:
+                  cond->rho = O_LE, strcpy(opstr, mpl->image); break;
+               case T_EQ:
+                  cond->rho = O_EQ, strcpy(opstr, mpl->image); break;
+               case T_GE:
+                  cond->rho = O_GE, strcpy(opstr, mpl->image); break;
+               case T_GT:
+                  cond->rho = O_GT, strcpy(opstr, mpl->image); break;
+               case T_NE:
+                  cond->rho = O_NE, strcpy(opstr, mpl->image); break;
+               default:
+                  xassert(mpl->token != mpl->token);
+            }
+            xassert(strlen(opstr) < sizeof(opstr));
+            cond->code = NULL;
+            cond->next = NULL;
+            if (par->cond == NULL)
+               par->cond = cond;
+            else
+            {  for (temp = par->cond; temp->next != NULL; temp =
+                  temp->next);
+               temp->next = cond;
+            }
+#if 0 /* 13/VIII-2008 */
+            if (par->type == A_SYMBOLIC &&
+               !(cond->rho == O_EQ || cond->rho == O_NE))
+               error(mpl, "inequality restriction not allowed");
+#endif
+            get_token(mpl /* rho */);
+            /* parse an expression that follows relational operator */
+            cond->code = expression_5(mpl);
+            if (!(cond->code->type == A_NUMERIC ||
+                  cond->code->type == A_SYMBOLIC))
+               error(mpl, "expression following %s has invalid type",
+                  opstr);
+            xassert(cond->code->dim == 0);
+            /* convert to the parameter type, if necessary */
+            if (par->type != A_SYMBOLIC && cond->code->type ==
+               A_SYMBOLIC)
+               cond->code = make_unary(mpl, O_CVTNUM, cond->code,
+                  A_NUMERIC, 0);
+            if (par->type == A_SYMBOLIC && cond->code->type !=
+               A_SYMBOLIC)
+               cond->code = make_unary(mpl, O_CVTSYM, cond->code,
+                  A_SYMBOLIC, 0);
+         }
+         else if (mpl->token == T_IN || mpl->token == T_WITHIN)
+         {  /* restricting superset */
+            WITHIN *in, *temp;
+            if (mpl->token == T_WITHIN && !mpl->as_in)
+            {  warning(mpl, "keyword within understood as in");
+               mpl->as_in = 1;
+            }
+            get_token(mpl /* in */);
+            /* create new restricting superset list entry and append it
+               to the in-list */
+            in = alloc(WITHIN);
+            in->code = NULL;
+            in->next = NULL;
+            if (par->in == NULL)
+               par->in = in;
+            else
+            {  for (temp = par->in; temp->next != NULL; temp =
+                  temp->next);
+               temp->next = in;
+            }
+            /* parse an expression that follows 'in' */
+            in->code = expression_9(mpl);
+            if (in->code->type != A_ELEMSET)
+               error(mpl, "expression following in has invalid type");
+            xassert(in->code->dim > 0);
+            if (in->code->dim != 1)
+               error(mpl, "set expression following in must have dimens"
+                  "ion 1 rather than %d", in->code->dim);
+         }
+         else if (mpl->token == T_ASSIGN)
+         {  /* assignment expression */
+            if (!(par->assign == NULL && par->option == NULL))
+err:           error(mpl, "at most one := or default allowed");
+            get_token(mpl /* := */);
+            /* parse an expression that follows ':=' */
+            par->assign = expression_5(mpl);
+            /* the expression must be of numeric/symbolic type */
+            if (!(par->assign->type == A_NUMERIC ||
+                  par->assign->type == A_SYMBOLIC))
+               error(mpl, "expression following := has invalid type");
+            xassert(par->assign->dim == 0);
+            /* convert to the parameter type, if necessary */
+            if (par->type != A_SYMBOLIC && par->assign->type ==
+               A_SYMBOLIC)
+               par->assign = make_unary(mpl, O_CVTNUM, par->assign,
+                  A_NUMERIC, 0);
+            if (par->type == A_SYMBOLIC && par->assign->type !=
+               A_SYMBOLIC)
+               par->assign = make_unary(mpl, O_CVTSYM, par->assign,
+                  A_SYMBOLIC, 0);
+         }
+         else if (is_keyword(mpl, "default"))
+         {  /* expression for default value */
+            if (!(par->assign == NULL && par->option == NULL)) goto err;
+            get_token(mpl /* default */);
+            /* parse an expression that follows 'default' */
+            par->option = expression_5(mpl);
+            if (!(par->option->type == A_NUMERIC ||
+                  par->option->type == A_SYMBOLIC))
+               error(mpl, "expression following default has invalid typ"
+                  "e");
+            xassert(par->option->dim == 0);
+            /* convert to the parameter type, if necessary */
+            if (par->type != A_SYMBOLIC && par->option->type ==
+               A_SYMBOLIC)
+               par->option = make_unary(mpl, O_CVTNUM, par->option,
+                  A_NUMERIC, 0);
+            if (par->type == A_SYMBOLIC && par->option->type !=
+               A_SYMBOLIC)
+               par->option = make_unary(mpl, O_CVTSYM, par->option,
+                  A_SYMBOLIC, 0);
+         }
+         else
+            error(mpl, "syntax error in parameter statement");
+      }
+      /* close the domain scope */
+      if (par->domain != NULL) close_scope(mpl, par->domain);
+      /* the parameter statement has been completely parsed */
+      xassert(mpl->token == T_SEMICOLON);
+      get_token(mpl /* ; */);
+      return par;
+}
+
+/*----------------------------------------------------------------------
+-- variable_statement - parse variable statement.
+--
+-- This routine parses variable statement using the syntax:
+--
+-- <variable statement> ::= var <symbolic name> <alias> <domain>
+--                          <attributes> ;
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <attributes> ::= <empty>
+-- <attributes> ::= <attributes> , integer
+-- <attributes> ::= <attributes> , binary
+-- <attributes> ::= <attributes> , <rho> <expression 5>
+-- <rho> ::= >= | <= | = | ==
+--
+-- Commae in <attributes> are optional and may be omitted anywhere. */
+
+VARIABLE *variable_statement(MPL *mpl)
+{     VARIABLE *var;
+      int integer_used = 0, binary_used = 0;
+      xassert(is_keyword(mpl, "var"));
+      if (mpl->flag_s)
+         error(mpl, "variable statement must precede solve statement");
+      get_token(mpl /* var */);
+      /* symbolic name must follow the keyword 'var' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model variable */
+      var = alloc(VARIABLE);
+      var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(var->name, mpl->image);
+      var->alias = NULL;
+      var->dim = 0;
+      var->domain = NULL;
+      var->type = A_NUMERIC;
+      var->lbnd = NULL;
+      var->ubnd = NULL;
+      var->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(var->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  var->domain = indexing_expression(mpl);
+         var->dim = domain_arity(mpl, var->domain);
+      }
+      /* include the variable name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, var->name);
+         avl_set_node_type(node, A_VARIABLE);
+         avl_set_node_link(node, (void *)var);
+      }
+      /* parse the list of optional attributes */
+      for (;;)
+      {  if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         if (is_keyword(mpl, "integer"))
+         {  if (integer_used)
+               error(mpl, "at most one integer allowed");
+            if (var->type != A_BINARY) var->type = A_INTEGER;
+            integer_used = 1;
+            get_token(mpl /* integer */);
+         }
+         else if (is_keyword(mpl, "binary"))
+bin:     {  if (binary_used)
+               error(mpl, "at most one binary allowed");
+            var->type = A_BINARY;
+            binary_used = 1;
+            get_token(mpl /* binary */);
+         }
+         else if (is_keyword(mpl, "logical"))
+         {  if (!mpl->as_binary)
+            {  warning(mpl, "keyword logical understood as binary");
+               mpl->as_binary = 1;
+            }
+            goto bin;
+         }
+         else if (is_keyword(mpl, "symbolic"))
+            error(mpl, "variable cannot be symbolic");
+         else if (mpl->token == T_GE)
+         {  /* lower bound */
+            if (var->lbnd != NULL)
+            {  if (var->lbnd == var->ubnd)
+                  error(mpl, "both fixed value and lower bound not allo"
+                     "wed");
+               else
+                  error(mpl, "at most one lower bound allowed");
+            }
+            get_token(mpl /* >= */);
+            /* parse an expression that specifies the lower bound */
+            var->lbnd = expression_5(mpl);
+            if (var->lbnd->type == A_SYMBOLIC)
+               var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
+                  A_NUMERIC, 0);
+            if (var->lbnd->type != A_NUMERIC)
+               error(mpl, "expression following >= has invalid type");
+            xassert(var->lbnd->dim == 0);
+         }
+         else if (mpl->token == T_LE)
+         {  /* upper bound */
+            if (var->ubnd != NULL)
+            {  if (var->ubnd == var->lbnd)
+                  error(mpl, "both fixed value and upper bound not allo"
+                     "wed");
+               else
+                  error(mpl, "at most one upper bound allowed");
+            }
+            get_token(mpl /* <= */);
+            /* parse an expression that specifies the upper bound */
+            var->ubnd = expression_5(mpl);
+            if (var->ubnd->type == A_SYMBOLIC)
+               var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd,
+                  A_NUMERIC, 0);
+            if (var->ubnd->type != A_NUMERIC)
+               error(mpl, "expression following <= has invalid type");
+            xassert(var->ubnd->dim == 0);
+         }
+         else if (mpl->token == T_EQ)
+         {  /* fixed value */
+            char opstr[8];
+            if (!(var->lbnd == NULL && var->ubnd == NULL))
+            {  if (var->lbnd == var->ubnd)
+                  error(mpl, "at most one fixed value allowed");
+               else if (var->lbnd != NULL)
+                  error(mpl, "both lower bound and fixed value not allo"
+                     "wed");
+               else
+                  error(mpl, "both upper bound and fixed value not allo"
+                     "wed");
+            }
+            strcpy(opstr, mpl->image);
+            xassert(strlen(opstr) < sizeof(opstr));
+            get_token(mpl /* = | == */);
+            /* parse an expression that specifies the fixed value */
+            var->lbnd = expression_5(mpl);
+            if (var->lbnd->type == A_SYMBOLIC)
+               var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
+                  A_NUMERIC, 0);
+            if (var->lbnd->type != A_NUMERIC)
+               error(mpl, "expression following %s has invalid type",
+                  opstr);
+            xassert(var->lbnd->dim == 0);
+            /* indicate that the variable is fixed, not bounded */
+            var->ubnd = var->lbnd;
+         }
+         else if (mpl->token == T_LT || mpl->token == T_GT ||
+                  mpl->token == T_NE)
+            error(mpl, "strict bound not allowed");
+         else
+            error(mpl, "syntax error in variable statement");
+      }
+      /* close the domain scope */
+      if (var->domain != NULL) close_scope(mpl, var->domain);
+      /* the variable statement has been completely parsed */
+      xassert(mpl->token == T_SEMICOLON);
+      get_token(mpl /* ; */);
+      return var;
+}
+
+/*----------------------------------------------------------------------
+-- constraint_statement - parse constraint statement.
+--
+-- This routine parses constraint statement using the syntax:
+--
+-- <constraint statement> ::= <subject to> <symbolic name> <alias>
+--                            <domain> : <constraint> ;
+-- <subject to> ::= <empty>
+-- <subject to> ::= subject to
+-- <subject to> ::= subj to
+-- <subject to> ::= s.t.
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <constraint> ::= <formula> , >= <formula>
+-- <constraint> ::= <formula> , <= <formula>
+-- <constraint> ::= <formula> , = <formula>
+-- <constraint> ::= <formula> , <= <formula> , <= <formula>
+-- <constraint> ::= <formula> , >= <formula> , >= <formula>
+-- <formula> ::= <expression 5>
+--
+-- Commae in <constraint> are optional and may be omitted anywhere. */
+
+CONSTRAINT *constraint_statement(MPL *mpl)
+{     CONSTRAINT *con;
+      CODE *first, *second, *third;
+      int rho;
+      char opstr[8];
+      if (mpl->flag_s)
+         error(mpl, "constraint statement must precede solve statement")
+            ;
+      if (is_keyword(mpl, "subject"))
+      {  get_token(mpl /* subject */);
+         if (!is_keyword(mpl, "to"))
+            error(mpl, "keyword subject to incomplete");
+         get_token(mpl /* to */);
+      }
+      else if (is_keyword(mpl, "subj"))
+      {  get_token(mpl /* subj */);
+         if (!is_keyword(mpl, "to"))
+            error(mpl, "keyword subj to incomplete");
+         get_token(mpl /* to */);
+      }
+      else if (mpl->token == T_SPTP)
+         get_token(mpl /* s.t. */);
+      /* the current token must be symbolic name of constraint */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model constraint */
+      con = alloc(CONSTRAINT);
+      con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(con->name, mpl->image);
+      con->alias = NULL;
+      con->dim = 0;
+      con->domain = NULL;
+      con->type = A_CONSTRAINT;
+      con->code = NULL;
+      con->lbnd = NULL;
+      con->ubnd = NULL;
+      con->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(con->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  con->domain = indexing_expression(mpl);
+         con->dim = domain_arity(mpl, con->domain);
+      }
+      /* include the constraint name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, con->name);
+         avl_set_node_type(node, A_CONSTRAINT);
+         avl_set_node_link(node, (void *)con);
+      }
+      /* the colon must precede the first expression */
+      if (mpl->token != T_COLON)
+         error(mpl, "colon missing where expected");
+      get_token(mpl /* : */);
+      /* parse the first expression */
+      first = expression_5(mpl);
+      if (first->type == A_SYMBOLIC)
+         first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0);
+      if (!(first->type == A_NUMERIC || first->type == A_FORMULA))
+         error(mpl, "expression following colon has invalid type");
+      xassert(first->dim == 0);
+      /* relational operator must follow the first expression */
+      if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      switch (mpl->token)
+      {  case T_LE:
+         case T_GE:
+         case T_EQ:
+            break;
+         case T_LT:
+         case T_GT:
+         case T_NE:
+            error(mpl, "strict inequality not allowed");
+         case T_SEMICOLON:
+            error(mpl, "constraint must be equality or inequality");
+         default:
+            goto err;
+      }
+      rho = mpl->token;
+      strcpy(opstr, mpl->image);
+      xassert(strlen(opstr) < sizeof(opstr));
+      get_token(mpl /* rho */);
+      /* parse the second expression */
+      second = expression_5(mpl);
+      if (second->type == A_SYMBOLIC)
+         second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
+      if (!(second->type == A_NUMERIC || second->type == A_FORMULA))
+         error(mpl, "expression following %s has invalid type", opstr);
+      xassert(second->dim == 0);
+      /* check a token that follow the second expression */
+      if (mpl->token == T_COMMA)
+      {  get_token(mpl /* , */);
+         if (mpl->token == T_SEMICOLON) goto err;
+      }
+      if (mpl->token == T_LT || mpl->token == T_LE ||
+          mpl->token == T_EQ || mpl->token == T_GE ||
+          mpl->token == T_GT || mpl->token == T_NE)
+      {  /* it is another relational operator, therefore the constraint
+            is double inequality */
+         if (rho == T_EQ || mpl->token != rho)
+            error(mpl, "double inequality must be ... <= ... <= ... or "
+               "... >= ... >= ...");
+         /* the first expression cannot be linear form */
+         if (first->type == A_FORMULA)
+            error(mpl, "leftmost expression in double inequality cannot"
+               " be linear form");
+         get_token(mpl /* rho */);
+         /* parse the third expression */
+         third = expression_5(mpl);
+         if (third->type == A_SYMBOLIC)
+            third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
+         if (!(third->type == A_NUMERIC || third->type == A_FORMULA))
+            error(mpl, "rightmost expression in double inequality const"
+               "raint has invalid type");
+         xassert(third->dim == 0);
+         /* the third expression also cannot be linear form */
+         if (third->type == A_FORMULA)
+            error(mpl, "rightmost expression in double inequality canno"
+               "t be linear form");
+      }
+      else
+      {  /* the constraint is equality or single inequality */
+         third = NULL;
+      }
+      /* close the domain scope */
+      if (con->domain != NULL) close_scope(mpl, con->domain);
+      /* convert all expressions to linear form, if necessary */
+      if (first->type != A_FORMULA)
+         first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0);
+      if (second->type != A_FORMULA)
+         second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0);
+      if (third != NULL)
+         third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0);
+      /* arrange expressions in the constraint */
+      if (third == NULL)
+      {  /* the constraint is equality or single inequality */
+         switch (rho)
+         {  case T_LE:
+               /* first <= second */
+               con->code = first;
+               con->lbnd = NULL;
+               con->ubnd = second;
+               break;
+            case T_GE:
+               /* first >= second */
+               con->code = first;
+               con->lbnd = second;
+               con->ubnd = NULL;
+               break;
+            case T_EQ:
+               /* first = second */
+               con->code = first;
+               con->lbnd = second;
+               con->ubnd = second;
+               break;
+            default:
+               xassert(rho != rho);
+         }
+      }
+      else
+      {  /* the constraint is double inequality */
+         switch (rho)
+         {  case T_LE:
+               /* first <= second <= third */
+               con->code = second;
+               con->lbnd = first;
+               con->ubnd = third;
+               break;
+            case T_GE:
+               /* first >= second >= third */
+               con->code = second;
+               con->lbnd = third;
+               con->ubnd = first;
+               break;
+            default:
+               xassert(rho != rho);
+         }
+      }
+      /* the constraint statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+err:     error(mpl, "syntax error in constraint statement");
+      get_token(mpl /* ; */);
+      return con;
+}
+
+/*----------------------------------------------------------------------
+-- objective_statement - parse objective statement.
+--
+-- This routine parses objective statement using the syntax:
+--
+-- <objective statement> ::= <verb> <symbolic name> <alias> <domain> :
+--                           <formula> ;
+-- <verb> ::= minimize
+-- <verb> ::= maximize
+-- <alias> ::= <empty>
+-- <alias> ::= <string literal>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <formula> ::= <expression 5> */
+
+CONSTRAINT *objective_statement(MPL *mpl)
+{     CONSTRAINT *obj;
+      int type;
+      if (is_keyword(mpl, "minimize"))
+         type = A_MINIMIZE;
+      else if (is_keyword(mpl, "maximize"))
+         type = A_MAXIMIZE;
+      else
+         xassert(mpl != mpl);
+      if (mpl->flag_s)
+         error(mpl, "objective statement must precede solve statement");
+      get_token(mpl /* minimize | maximize */);
+      /* symbolic name must follow the verb 'minimize' or 'maximize' */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create model objective */
+      obj = alloc(CONSTRAINT);
+      obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(obj->name, mpl->image);
+      obj->alias = NULL;
+      obj->dim = 0;
+      obj->domain = NULL;
+      obj->type = type;
+      obj->code = NULL;
+      obj->lbnd = NULL;
+      obj->ubnd = NULL;
+      obj->array = NULL;
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(obj->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  obj->domain = indexing_expression(mpl);
+         obj->dim = domain_arity(mpl, obj->domain);
+      }
+      /* include the constraint name in the symbolic names table */
+      {  AVLNODE *node;
+         node = avl_insert_node(mpl->tree, obj->name);
+         avl_set_node_type(node, A_CONSTRAINT);
+         avl_set_node_link(node, (void *)obj);
+      }
+      /* the colon must precede the objective expression */
+      if (mpl->token != T_COLON)
+         error(mpl, "colon missing where expected");
+      get_token(mpl /* : */);
+      /* parse the objective expression */
+      obj->code = expression_5(mpl);
+      if (obj->code->type == A_SYMBOLIC)
+         obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0);
+      if (obj->code->type == A_NUMERIC)
+         obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0);
+      if (obj->code->type != A_FORMULA)
+         error(mpl, "expression following colon has invalid type");
+      xassert(obj->code->dim == 0);
+      /* close the domain scope */
+      if (obj->domain != NULL) close_scope(mpl, obj->domain);
+      /* the objective statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in objective statement");
+      get_token(mpl /* ; */);
+      return obj;
+}
+
+#if 1 /* 11/II-2008 */
+/***********************************************************************
+*  table_statement - parse table statement
+*
+*  This routine parses table statement using the syntax:
+*
+*  <table statement> ::= <input table statement>
+*  <table statement> ::= <output table statement>
+*
+*  <input table statement> ::=
+*        table <table name> <alias> IN <argument list> :
+*        <input set> [ <field list> ] , <input list> ;
+*  <alias> ::= <empty>
+*  <alias> ::= <string literal>
+*  <argument list> ::= <expression 5>
+*  <argument list> ::= <argument list> <expression 5>
+*  <argument list> ::= <argument list> , <expression 5>
+*  <input set> ::= <empty>
+*  <input set> ::= <set name> <-
+*  <field list> ::= <field name>
+*  <field list> ::= <field list> , <field name>
+*  <input list> ::= <input item>
+*  <input list> ::= <input list> , <input item>
+*  <input item> ::= <parameter name>
+*  <input item> ::= <parameter name> ~ <field name>
+*
+*  <output table statement> ::=
+*        table <table name> <alias> <domain> OUT <argument list> :
+*        <output list> ;
+*  <domain> ::= <indexing expression>
+*  <output list> ::= <output item>
+*  <output list> ::= <output list> , <output item>
+*  <output item> ::= <expression 5>
+*  <output item> ::= <expression 5> ~ <field name> */
+
+TABLE *table_statement(MPL *mpl)
+{     TABLE *tab;
+      TABARG *last_arg, *arg;
+      TABFLD *last_fld, *fld;
+      TABIN *last_in, *in;
+      TABOUT *last_out, *out;
+      AVLNODE *node;
+      int nflds;
+      char name[MAX_LENGTH+1];
+      xassert(is_keyword(mpl, "table"));
+      get_token(mpl /* solve */);
+      /* symbolic name must follow the keyword table */
+      if (mpl->token == T_NAME)
+         ;
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "symbolic name missing where expected");
+      /* there must be no other object with the same name */
+      if (avl_find_node(mpl->tree, mpl->image) != NULL)
+         error(mpl, "%s multiply declared", mpl->image);
+      /* create data table */
+      tab = alloc(TABLE);
+      tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+      strcpy(tab->name, mpl->image);
+      get_token(mpl /* <symbolic name> */);
+      /* parse optional alias */
+      if (mpl->token == T_STRING)
+      {  tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(tab->alias, mpl->image);
+         get_token(mpl /* <string literal> */);
+      }
+      else
+         tab->alias = NULL;
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  /* this is output table */
+         tab->type = A_OUTPUT;
+         tab->u.out.domain = indexing_expression(mpl);
+         if (!is_keyword(mpl, "OUT"))
+            error(mpl, "keyword OUT missing where expected");
+         get_token(mpl /* OUT */);
+      }
+      else
+      {  /* this is input table */
+         tab->type = A_INPUT;
+         if (!is_keyword(mpl, "IN"))
+            error(mpl, "keyword IN missing where expected");
+         get_token(mpl /* IN */);
+      }
+      /* parse argument list */
+      tab->arg = last_arg = NULL;
+      for (;;)
+      {  /* create argument list entry */
+         arg = alloc(TABARG);
+         /* parse argument expression */
+         if (mpl->token == T_COMMA || mpl->token == T_COLON ||
+             mpl->token == T_SEMICOLON)
+            error(mpl, "argument expression missing where expected");
+         arg->code = expression_5(mpl);
+         /* convert the result to symbolic type, if necessary */
+         if (arg->code->type == A_NUMERIC)
+            arg->code =
+               make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0);
+         /* check that now the result is of symbolic type */
+         if (arg->code->type != A_SYMBOLIC)
+            error(mpl, "argument expression has invalid type");
+         /* add the entry to the end of the list */
+         arg->next = NULL;
+         if (last_arg == NULL)
+            tab->arg = arg;
+         else
+            last_arg->next = arg;
+         last_arg = arg;
+         /* argument expression has been parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON)
+            break;
+      }
+      xassert(tab->arg != NULL);
+      /* argument list must end with colon */
+      if (mpl->token == T_COLON)
+         get_token(mpl /* : */);
+      else
+         error(mpl, "colon missing where expected");
+      /* parse specific part of the table statement */
+      switch (tab->type)
+      {  case A_INPUT:  goto input_table;
+         case A_OUTPUT: goto output_table;
+         default:       xassert(tab != tab);
+      }
+input_table:
+      /* parse optional set name */
+      if (mpl->token == T_NAME)
+      {  node = avl_find_node(mpl->tree, mpl->image);
+         if (node == NULL)
+            error(mpl, "%s not defined", mpl->image);
+         if (avl_get_node_type(node) != A_SET)
+            error(mpl, "%s not a set", mpl->image);
+         tab->u.in.set = (SET *)avl_get_node_link(node);
+         if (tab->u.in.set->assign != NULL)
+            error(mpl, "%s needs no data", mpl->image);
+         if (tab->u.in.set->dim != 0)
+            error(mpl, "%s must be a simple set", mpl->image);
+         get_token(mpl /* <symbolic name> */);
+         if (mpl->token == T_INPUT)
+            get_token(mpl /* <- */);
+         else
+            error(mpl, "delimiter <- missing where expected");
+      }
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         tab->u.in.set = NULL;
+      /* parse field list */
+      tab->u.in.fld = last_fld = NULL;
+      nflds = 0;
+      if (mpl->token == T_LBRACKET)
+         get_token(mpl /* [ */);
+      else
+         error(mpl, "field list missing where expected");
+      for (;;)
+      {  /* create field list entry */
+         fld = alloc(TABFLD);
+         /* parse field name */
+         if (mpl->token == T_NAME)
+            ;
+         else if (is_reserved(mpl))
+            error(mpl,
+               "invalid use of reserved keyword %s", mpl->image);
+         else
+            error(mpl, "field name missing where expected");
+         fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
+         strcpy(fld->name, mpl->image);
+         get_token(mpl /* <symbolic name> */);
+         /* add the entry to the end of the list */
+         fld->next = NULL;
+         if (last_fld == NULL)
+            tab->u.in.fld = fld;
+         else
+            last_fld->next = fld;
+         last_fld = fld;
+         nflds++;
+         /* field name has been parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_RBRACKET)
+            break;
+         else
+            error(mpl, "syntax error in field list");
+      }
+      /* check that the set dimen is equal to the number of fields */
+      if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds)
+         error(mpl, "there must be %d field%s rather than %d",
+            tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s",
+            nflds);
+      get_token(mpl /* ] */);
+      /* parse optional input list */
+      tab->u.in.list = last_in = NULL;
+      while (mpl->token == T_COMMA)
+      {  get_token(mpl /* , */);
+         /* create input list entry */
+         in = alloc(TABIN);
+         /* parse parameter name */
+         if (mpl->token == T_NAME)
+            ;
+         else if (is_reserved(mpl))
+            error(mpl,
+               "invalid use of reserved keyword %s", mpl->image);
+         else
+            error(mpl, "parameter name missing where expected");
+         node = avl_find_node(mpl->tree, mpl->image);
+         if (node == NULL)
+            error(mpl, "%s not defined", mpl->image);
+         if (avl_get_node_type(node) != A_PARAMETER)
+            error(mpl, "%s not a parameter", mpl->image);
+         in->par = (PARAMETER *)avl_get_node_link(node);
+         if (in->par->dim != nflds)
+            error(mpl, "%s must have %d subscript%s rather than %d",
+               mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim);
+         if (in->par->assign != NULL)
+            error(mpl, "%s needs no data", mpl->image);
+         get_token(mpl /* <symbolic name> */);
+         /* parse optional field name */
+         if (mpl->token == T_TILDE)
+         {  get_token(mpl /* ~ */);
+            /* parse field name */
+            if (mpl->token == T_NAME)
+               ;
+            else if (is_reserved(mpl))
+               error(mpl,
+                  "invalid use of reserved keyword %s", mpl->image);
+            else
+               error(mpl, "field name missing where expected");
+            xassert(strlen(mpl->image) < sizeof(name));
+            strcpy(name, mpl->image);
+            get_token(mpl /* <symbolic name> */);
+         }
+         else
+         {  /* field name is the same as the parameter name */
+            xassert(strlen(in->par->name) < sizeof(name));
+            strcpy(name, in->par->name);
+         }
+         /* assign field name */
+         in->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
+         strcpy(in->name, name);
+         /* add the entry to the end of the list */
+         in->next = NULL;
+         if (last_in == NULL)
+            tab->u.in.list = in;
+         else
+            last_in->next = in;
+         last_in = in;
+      }
+      goto end_of_table;
+output_table:
+      /* parse output list */
+      tab->u.out.list = last_out = NULL;
+      for (;;)
+      {  /* create output list entry */
+         out = alloc(TABOUT);
+         /* parse expression */
+         if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON)
+            error(mpl, "expression missing where expected");
+         if (mpl->token == T_NAME)
+         {  xassert(strlen(mpl->image) < sizeof(name));
+            strcpy(name, mpl->image);
+         }
+         else
+            name[0] = '\0';
+         out->code = expression_5(mpl);
+         /* parse optional field name */
+         if (mpl->token == T_TILDE)
+         {  get_token(mpl /* ~ */);
+            /* parse field name */
+            if (mpl->token == T_NAME)
+               ;
+            else if (is_reserved(mpl))
+               error(mpl,
+                  "invalid use of reserved keyword %s", mpl->image);
+            else
+               error(mpl, "field name missing where expected");
+            xassert(strlen(mpl->image) < sizeof(name));
+            strcpy(name, mpl->image);
+            get_token(mpl /* <symbolic name> */);
+         }
+         /* assign field name */
+         if (name[0] == '\0')
+            error(mpl, "field name required");
+         out->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
+         strcpy(out->name, name);
+         /* add the entry to the end of the list */
+         out->next = NULL;
+         if (last_out == NULL)
+            tab->u.out.list = out;
+         else
+            last_out->next = out;
+         last_out = out;
+         /* output item has been parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == T_SEMICOLON)
+            break;
+         else
+            error(mpl, "syntax error in output list");
+      }
+      /* close the domain scope */
+      close_scope(mpl,tab->u.out.domain);
+end_of_table:
+      /* the table statement must end with semicolon */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in table statement");
+      get_token(mpl /* ; */);
+      return tab;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- solve_statement - parse solve statement.
+--
+-- This routine parses solve statement using the syntax:
+--
+-- <solve statement> ::= solve ;
+--
+-- The solve statement can be used at most once. */
+
+void *solve_statement(MPL *mpl)
+{     xassert(is_keyword(mpl, "solve"));
+      if (mpl->flag_s)
+         error(mpl, "at most one solve statement allowed");
+      mpl->flag_s = 1;
+      get_token(mpl /* solve */);
+      /* semicolon must follow solve statement */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in solve statement");
+      get_token(mpl /* ; */);
+      return NULL;
+}
+
+/*----------------------------------------------------------------------
+-- check_statement - parse check statement.
+--
+-- This routine parses check statement using the syntax:
+--
+-- <check statement> ::= check <domain> : <expression 13> ;
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+--
+-- If <domain> is omitted, colon following it may also be omitted. */
+
+CHECK *check_statement(MPL *mpl)
+{     CHECK *chk;
+      xassert(is_keyword(mpl, "check"));
+      /* create check descriptor */
+      chk = alloc(CHECK);
+      chk->domain = NULL;
+      chk->code = NULL;
+      get_token(mpl /* check */);
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  chk->domain = indexing_expression(mpl);
+#if 0
+         if (mpl->token != T_COLON)
+            error(mpl, "colon missing where expected");
+#endif
+      }
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse logical expression */
+      chk->code = expression_13(mpl);
+      if (chk->code->type != A_LOGICAL)
+         error(mpl, "expression has invalid type");
+      xassert(chk->code->dim == 0);
+      /* close the domain scope */
+      if (chk->domain != NULL) close_scope(mpl, chk->domain);
+      /* the check statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in check statement");
+      get_token(mpl /* ; */);
+      return chk;
+}
+
+#if 1 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- display_statement - parse display statement.
+--
+-- This routine parses display statement using the syntax:
+--
+-- <display statement> ::= display <domain> : <display list> ;
+-- <display statement> ::= display <domain> <display list> ;
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <display list> ::= <display entry>
+-- <display list> ::= <display list> , <display entry>
+-- <display entry> ::= <dummy index>
+-- <display entry> ::= <set name>
+-- <display entry> ::= <set name> [ <subscript list> ]
+-- <display entry> ::= <parameter name>
+-- <display entry> ::= <parameter name> [ <subscript list> ]
+-- <display entry> ::= <variable name>
+-- <display entry> ::= <variable name> [ <subscript list> ]
+-- <display entry> ::= <constraint name>
+-- <display entry> ::= <constraint name> [ <subscript list> ]
+-- <display entry> ::= <expression 13> */
+
+DISPLAY *display_statement(MPL *mpl)
+{     DISPLAY *dpy;
+      DISPLAY1 *entry, *last_entry;
+      xassert(is_keyword(mpl, "display"));
+      /* create display descriptor */
+      dpy = alloc(DISPLAY);
+      dpy->domain = NULL;
+      dpy->list = last_entry = NULL;
+      get_token(mpl /* display */);
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+         dpy->domain = indexing_expression(mpl);
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse display list */
+      for (;;)
+      {  /* create new display entry */
+         entry = alloc(DISPLAY1);
+         entry->type = 0;
+         entry->next = NULL;
+         /* and append it to the display list */
+         if (dpy->list == NULL)
+            dpy->list = entry;
+         else
+            last_entry->next = entry;
+         last_entry = entry;
+         /* parse display entry */
+         if (mpl->token == T_NAME)
+         {  AVLNODE *node;
+            int next_token;
+            get_token(mpl /* <symbolic name> */);
+            next_token = mpl->token;
+            unget_token(mpl);
+            if (!(next_token == T_COMMA || next_token == T_SEMICOLON))
+            {  /* symbolic name begins expression */
+               goto expr;
+            }
+            /* display entry is dummy index or model object */
+            node = avl_find_node(mpl->tree, mpl->image);
+            if (node == NULL)
+               error(mpl, "%s not defined", mpl->image);
+            entry->type = avl_get_node_type(node);
+            switch (avl_get_node_type(node))
+            {  case A_INDEX:
+                  entry->u.slot =
+                     (DOMAIN_SLOT *)avl_get_node_link(node);
+                  break;
+               case A_SET:
+                  entry->u.set = (SET *)avl_get_node_link(node);
+                  break;
+               case A_PARAMETER:
+                  entry->u.par = (PARAMETER *)avl_get_node_link(node);
+                  break;
+               case A_VARIABLE:
+                  entry->u.var = (VARIABLE *)avl_get_node_link(node);
+                  if (!mpl->flag_s)
+                     error(mpl, "invalid reference to variable %s above"
+                        " solve statement", entry->u.var->name);
+                  break;
+               case A_CONSTRAINT:
+                  entry->u.con = (CONSTRAINT *)avl_get_node_link(node);
+                  if (!mpl->flag_s)
+                     error(mpl, "invalid reference to %s %s above solve"
+                        " statement",
+                        entry->u.con->type == A_CONSTRAINT ?
+                        "constraint" : "objective", entry->u.con->name);
+                  break;
+               default:
+                  xassert(node != node);
+            }
+            get_token(mpl /* <symbolic name> */);
+         }
+         else
+expr:    {  /* display entry is expression */
+            entry->type = A_EXPRESSION;
+            entry->u.code = expression_13(mpl);
+         }
+         /* check a token that follows the entry parsed */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else
+            break;
+      }
+      /* close the domain scope */
+      if (dpy->domain != NULL) close_scope(mpl, dpy->domain);
+      /* the display statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in display statement");
+      get_token(mpl /* ; */);
+      return dpy;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- printf_statement - parse printf statement.
+--
+-- This routine parses print statement using the syntax:
+--
+-- <printf statement> ::= <printf clause> ;
+-- <printf statement> ::= <printf clause> > <file name> ;
+-- <printf statement> ::= <printf clause> >> <file name> ;
+-- <printf clause> ::= printf <domain> : <format> <printf list>
+-- <printf clause> ::= printf <domain> <format> <printf list>
+-- <domain> ::= <empty>
+-- <domain> ::= <indexing expression>
+-- <format> ::= <expression 5>
+-- <printf list> ::= <empty>
+-- <printf list> ::= <printf list> , <printf entry>
+-- <printf entry> ::= <expression 9>
+-- <file name> ::= <expression 5> */
+
+PRINTF *printf_statement(MPL *mpl)
+{     PRINTF *prt;
+      PRINTF1 *entry, *last_entry;
+      xassert(is_keyword(mpl, "printf"));
+      /* create printf descriptor */
+      prt = alloc(PRINTF);
+      prt->domain = NULL;
+      prt->fmt = NULL;
+      prt->list = last_entry = NULL;
+      get_token(mpl /* printf */);
+      /* parse optional indexing expression */
+      if (mpl->token == T_LBRACE)
+      {  prt->domain = indexing_expression(mpl);
+#if 0
+         if (mpl->token != T_COLON)
+            error(mpl, "colon missing where expected");
+#endif
+      }
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse expression for format string */
+      prt->fmt = expression_5(mpl);
+      /* convert it to symbolic type, if necessary */
+      if (prt->fmt->type == A_NUMERIC)
+         prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0);
+      /* check that now the expression is of symbolic type */
+      if (prt->fmt->type != A_SYMBOLIC)
+         error(mpl, "format expression has invalid type");
+      /* parse printf list */
+      while (mpl->token == T_COMMA)
+      {  get_token(mpl /* , */);
+         /* create new printf entry */
+         entry = alloc(PRINTF1);
+         entry->code = NULL;
+         entry->next = NULL;
+         /* and append it to the printf list */
+         if (prt->list == NULL)
+            prt->list = entry;
+         else
+            last_entry->next = entry;
+         last_entry = entry;
+         /* parse printf entry */
+         entry->code = expression_9(mpl);
+         if (!(entry->code->type == A_NUMERIC ||
+               entry->code->type == A_SYMBOLIC ||
+               entry->code->type == A_LOGICAL))
+            error(mpl, "only numeric, symbolic, or logical expression a"
+               "llowed");
+      }
+      /* close the domain scope */
+      if (prt->domain != NULL) close_scope(mpl, prt->domain);
+#if 1 /* 14/VII-2006 */
+      /* parse optional redirection */
+      prt->fname = NULL, prt->app = 0;
+      if (mpl->token == T_GT || mpl->token == T_APPEND)
+      {  prt->app = (mpl->token == T_APPEND);
+         get_token(mpl /* > or >> */);
+         /* parse expression for file name string */
+         prt->fname = expression_5(mpl);
+         /* convert it to symbolic type, if necessary */
+         if (prt->fname->type == A_NUMERIC)
+            prt->fname = make_unary(mpl, O_CVTSYM, prt->fname,
+               A_SYMBOLIC, 0);
+         /* check that now the expression is of symbolic type */
+         if (prt->fname->type != A_SYMBOLIC)
+            error(mpl, "file name expression has invalid type");
+      }
+#endif
+      /* the printf statement has been completely parsed */
+      if (mpl->token != T_SEMICOLON)
+         error(mpl, "syntax error in printf statement");
+      get_token(mpl /* ; */);
+      return prt;
+}
+
+/*----------------------------------------------------------------------
+-- for_statement - parse for statement.
+--
+-- This routine parses for statement using the syntax:
+--
+-- <for statement> ::= for <domain> <statement>
+-- <for statement> ::= for <domain> { <statement list> }
+-- <domain> ::= <indexing expression>
+-- <statement list> ::= <empty>
+-- <statement list> ::= <statement list> <statement>
+-- <statement> ::= <check statement>
+-- <statement> ::= <display statement>
+-- <statement> ::= <printf statement>
+-- <statement> ::= <for statement> */
+
+FOR *for_statement(MPL *mpl)
+{     FOR *fur;
+      STATEMENT *stmt, *last_stmt;
+      xassert(is_keyword(mpl, "for"));
+      /* create for descriptor */
+      fur = alloc(FOR);
+      fur->domain = NULL;
+      fur->list = last_stmt = NULL;
+      get_token(mpl /* for */);
+      /* parse indexing expression */
+      if (mpl->token != T_LBRACE)
+         error(mpl, "indexing expression missing where expected");
+      fur->domain = indexing_expression(mpl);
+      /* skip optional colon */
+      if (mpl->token == T_COLON) get_token(mpl /* : */);
+      /* parse for statement body */
+      if (mpl->token != T_LBRACE)
+      {  /* parse simple statement */
+         fur->list = simple_statement(mpl, 1);
+      }
+      else
+      {  /* parse compound statement */
+         get_token(mpl /* { */);
+         while (mpl->token != T_RBRACE)
+         {  /* parse statement */
+            stmt = simple_statement(mpl, 1);
+            /* and append it to the end of the statement list */
+            if (last_stmt == NULL)
+               fur->list = stmt;
+            else
+               last_stmt->next = stmt;
+            last_stmt = stmt;
+         }
+         get_token(mpl /* } */);
+      }
+      /* close the domain scope */
+      xassert(fur->domain != NULL);
+      close_scope(mpl, fur->domain);
+      /* the for statement has been completely parsed */
+      return fur;
+}
+
+/*----------------------------------------------------------------------
+-- end_statement - parse end statement.
+--
+-- This routine parses end statement using the syntax:
+--
+-- <end statement> ::= end ; <eof> */
+
+void end_statement(MPL *mpl)
+{     if (!mpl->flag_d && is_keyword(mpl, "end") ||
+           mpl->flag_d && is_literal(mpl, "end"))
+      {  get_token(mpl /* end */);
+         if (mpl->token == T_SEMICOLON)
+            get_token(mpl /* ; */);
+         else
+            warning(mpl, "no semicolon following end statement; missing"
+               " semicolon inserted");
+      }
+      else
+         warning(mpl, "unexpected end of file; missing end statement in"
+            "serted");
+      if (mpl->token != T_EOF)
+         warning(mpl, "some text detected beyond end statement; text ig"
+            "nored");
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- simple_statement - parse simple statement.
+--
+-- This routine parses simple statement using the syntax:
+--
+-- <statement> ::= <set statement>
+-- <statement> ::= <parameter statement>
+-- <statement> ::= <variable statement>
+-- <statement> ::= <constraint statement>
+-- <statement> ::= <objective statement>
+-- <statement> ::= <solve statement>
+-- <statement> ::= <check statement>
+-- <statement> ::= <display statement>
+-- <statement> ::= <printf statement>
+-- <statement> ::= <for statement>
+--
+-- If the flag spec is set, some statements cannot be used. */
+
+STATEMENT *simple_statement(MPL *mpl, int spec)
+{     STATEMENT *stmt;
+      stmt = alloc(STATEMENT);
+      stmt->line = mpl->line;
+      stmt->next = NULL;
+      if (is_keyword(mpl, "set"))
+      {  if (spec)
+            error(mpl, "set statement not allowed here");
+         stmt->type = A_SET;
+         stmt->u.set = set_statement(mpl);
+      }
+      else if (is_keyword(mpl, "param"))
+      {  if (spec)
+            error(mpl, "parameter statement not allowed here");
+         stmt->type = A_PARAMETER;
+         stmt->u.par = parameter_statement(mpl);
+      }
+      else if (is_keyword(mpl, "var"))
+      {  if (spec)
+            error(mpl, "variable statement not allowed here");
+         stmt->type = A_VARIABLE;
+         stmt->u.var = variable_statement(mpl);
+      }
+      else if (is_keyword(mpl, "subject") ||
+               is_keyword(mpl, "subj") ||
+               mpl->token == T_SPTP)
+      {  if (spec)
+            error(mpl, "constraint statement not allowed here");
+         stmt->type = A_CONSTRAINT;
+         stmt->u.con = constraint_statement(mpl);
+      }
+      else if (is_keyword(mpl, "minimize") ||
+               is_keyword(mpl, "maximize"))
+      {  if (spec)
+            error(mpl, "objective statement not allowed here");
+         stmt->type = A_CONSTRAINT;
+         stmt->u.con = objective_statement(mpl);
+      }
+#if 1 /* 11/II-2008 */
+      else if (is_keyword(mpl, "table"))
+      {  if (spec)
+            error(mpl, "table statement not allowed here");
+         stmt->type = A_TABLE;
+         stmt->u.tab = table_statement(mpl);
+      }
+#endif
+      else if (is_keyword(mpl, "solve"))
+      {  if (spec)
+            error(mpl, "solve statement not allowed here");
+         stmt->type = A_SOLVE;
+         stmt->u.slv = solve_statement(mpl);
+      }
+      else if (is_keyword(mpl, "check"))
+      {  stmt->type = A_CHECK;
+         stmt->u.chk = check_statement(mpl);
+      }
+      else if (is_keyword(mpl, "display"))
+      {  stmt->type = A_DISPLAY;
+         stmt->u.dpy = display_statement(mpl);
+      }
+      else if (is_keyword(mpl, "printf"))
+      {  stmt->type = A_PRINTF;
+         stmt->u.prt = printf_statement(mpl);
+      }
+      else if (is_keyword(mpl, "for"))
+      {  stmt->type = A_FOR;
+         stmt->u.fur = for_statement(mpl);
+      }
+      else if (mpl->token == T_NAME)
+      {  if (spec)
+            error(mpl, "constraint statement not allowed here");
+         stmt->type = A_CONSTRAINT;
+         stmt->u.con = constraint_statement(mpl);
+      }
+      else if (is_reserved(mpl))
+         error(mpl, "invalid use of reserved keyword %s", mpl->image);
+      else
+         error(mpl, "syntax error in model section");
+      return stmt;
+}
+
+/*----------------------------------------------------------------------
+-- model_section - parse model section.
+--
+-- This routine parses model section using the syntax:
+--
+-- <model section> ::= <empty>
+-- <model section> ::= <model section> <statement>
+--
+-- Parsing model section is terminated by either the keyword 'data', or
+-- the keyword 'end', or the end of file. */
+
+void model_section(MPL *mpl)
+{     STATEMENT *stmt, *last_stmt;
+      xassert(mpl->model == NULL);
+      last_stmt = NULL;
+      while (!(mpl->token == T_EOF || is_keyword(mpl, "data") ||
+               is_keyword(mpl, "end")))
+      {  /* parse statement */
+         stmt = simple_statement(mpl, 0);
+         /* and append it to the end of the statement list */
+         if (last_stmt == NULL)
+            mpl->model = stmt;
+         else
+            last_stmt->next = stmt;
+         last_stmt = stmt;
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpmpl02.c
===================================================================
--- deps/glpk/src/glpmpl02.c	(revision 9)
+++ deps/glpk/src/glpmpl02.c	(revision 9)
@@ -0,0 +1,1205 @@
+/* glpmpl02.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glpmpl.h"
+
+/**********************************************************************/
+/* * *                  PROCESSING DATA SECTION                   * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_slice - create slice.
+--
+-- This routine creates a slice, which initially has no components. */
+
+SLICE *create_slice(MPL *mpl)
+{     SLICE *slice;
+      xassert(mpl == mpl);
+      slice = NULL;
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- expand_slice - append new component to slice.
+--
+-- This routine expands slice appending to it either a given symbol or
+-- null component, which becomes the last component of the slice. */
+
+SLICE *expand_slice
+(     MPL *mpl,
+      SLICE *slice,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+)
+{     SLICE *tail, *temp;
+      /* create a new component */
+      tail = dmp_get_atom(mpl->tuples, sizeof(SLICE));
+      tail->sym = sym;
+      tail->next = NULL;
+      /* and append it to the component list */
+      if (slice == NULL)
+         slice = tail;
+      else
+      {  for (temp = slice; temp->next != NULL; temp = temp->next);
+         temp->next = tail;
+      }
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- slice_dimen - determine dimension of slice.
+--
+-- This routine returns dimension of slice, which is number of all its
+-- components including null ones. */
+
+int slice_dimen
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+)
+{     SLICE *temp;
+      int dim;
+      xassert(mpl == mpl);
+      dim = 0;
+      for (temp = slice; temp != NULL; temp = temp->next) dim++;
+      return dim;
+}
+
+/*----------------------------------------------------------------------
+-- slice_arity - determine arity of slice.
+--
+-- This routine returns arity of slice, i.e. number of null components
+-- (indicated by asterisks) in the slice. */
+
+int slice_arity
+(     MPL *mpl,
+      SLICE *slice            /* not changed */
+)
+{     SLICE *temp;
+      int arity;
+      xassert(mpl == mpl);
+      arity = 0;
+      for (temp = slice; temp != NULL; temp = temp->next)
+         if (temp->sym == NULL) arity++;
+      return arity;
+}
+
+/*----------------------------------------------------------------------
+-- fake_slice - create fake slice of all asterisks.
+--
+-- This routine creates a fake slice of given dimension, which contains
+-- asterisks in all components. Zero dimension is allowed. */
+
+SLICE *fake_slice(MPL *mpl, int dim)
+{     SLICE *slice;
+      slice = create_slice(mpl);
+      while (dim-- > 0) slice = expand_slice(mpl, slice, NULL);
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- delete_slice - delete slice.
+--
+-- This routine deletes specified slice. */
+
+void delete_slice
+(     MPL *mpl,
+      SLICE *slice            /* destroyed */
+)
+{     SLICE *temp;
+      while (slice != NULL)
+      {  temp = slice;
+         slice = temp->next;
+         if (temp->sym != NULL) delete_symbol(mpl, temp->sym);
+xassert(sizeof(SLICE) == sizeof(TUPLE));
+         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- is_number - check if current token is number.
+--
+-- If the current token is a number, this routine returns non-zero.
+-- Otherwise zero is returned. */
+
+int is_number(MPL *mpl)
+{     return
+         mpl->token == T_NUMBER;
+}
+
+/*----------------------------------------------------------------------
+-- is_symbol - check if current token is symbol.
+--
+-- If the current token is suitable to be a symbol, the routine returns
+-- non-zero. Otherwise zero is returned. */
+
+int is_symbol(MPL *mpl)
+{     return
+         mpl->token == T_NUMBER ||
+         mpl->token == T_SYMBOL ||
+         mpl->token == T_STRING;
+}
+
+/*----------------------------------------------------------------------
+-- is_literal - check if current token is given symbolic literal.
+--
+-- If the current token is given symbolic literal, this routine returns
+-- non-zero. Otherwise zero is returned.
+--
+-- This routine is used on processing the data section in the same way
+-- as the routine is_keyword on processing the model section. */
+
+int is_literal(MPL *mpl, char *literal)
+{     return
+         is_symbol(mpl) && strcmp(mpl->image, literal) == 0;
+}
+
+/*----------------------------------------------------------------------
+-- read_number - read number.
+--
+-- This routine reads the current token, which must be a number, and
+-- returns its numeric value. */
+
+double read_number(MPL *mpl)
+{     double num;
+      xassert(is_number(mpl));
+      num = mpl->value;
+      get_token(mpl /* <number> */);
+      return num;
+}
+
+/*----------------------------------------------------------------------
+-- read_symbol - read symbol.
+--
+-- This routine reads the current token, which must be a symbol, and
+-- returns its symbolic value. */
+
+SYMBOL *read_symbol(MPL *mpl)
+{     SYMBOL *sym;
+      xassert(is_symbol(mpl));
+      if (is_number(mpl))
+         sym = create_symbol_num(mpl, mpl->value);
+      else
+         sym = create_symbol_str(mpl, create_string(mpl, mpl->image));
+      get_token(mpl /* <symbol> */);
+      return sym;
+}
+
+/*----------------------------------------------------------------------
+-- read_slice - read slice.
+--
+-- This routine reads slice using the syntax:
+--
+-- <slice> ::= [ <symbol list> ]
+-- <slice> ::= ( <symbol list> )
+-- <symbol list> ::= <symbol or star>
+-- <symbol list> ::= <symbol list> , <symbol or star>
+-- <symbol or star> ::= <symbol>
+-- <symbol or star> ::= *
+--
+-- The bracketed form of slice is used for members of multi-dimensional
+-- objects while the parenthesized form is used for elemental sets. */
+
+SLICE *read_slice
+(     MPL *mpl,
+      char *name,             /* not changed */
+      int dim
+)
+{     SLICE *slice;
+      int close;
+      xassert(name != NULL);
+      switch (mpl->token)
+      {  case T_LBRACKET:
+            close = T_RBRACKET;
+            break;
+         case T_LEFT:
+            xassert(dim > 0);
+            close = T_RIGHT;
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      if (dim == 0)
+         error(mpl, "%s cannot be subscripted", name);
+      get_token(mpl /* ( | [ */);
+      /* read slice components */
+      slice = create_slice(mpl);
+      for (;;)
+      {  /* the current token must be a symbol or asterisk */
+         if (is_symbol(mpl))
+            slice = expand_slice(mpl, slice, read_symbol(mpl));
+         else if (mpl->token == T_ASTERISK)
+         {  slice = expand_slice(mpl, slice, NULL);
+            get_token(mpl /* * */);
+         }
+         else
+            error(mpl, "number, symbol, or asterisk missing where expec"
+               "ted");
+         /* check a token that follows the symbol */
+         if (mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+         else if (mpl->token == close)
+            break;
+         else
+            error(mpl, "syntax error in slice");
+      }
+      /* number of slice components must be the same as the appropriate
+         dimension */
+      if (slice_dimen(mpl, slice) != dim)
+      {  switch (close)
+         {  case T_RBRACKET:
+               error(mpl, "%s must have %d subscript%s, not %d", name,
+                  dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice));
+               break;
+            case T_RIGHT:
+               error(mpl, "%s has dimension %d, not %d", name, dim,
+                  slice_dimen(mpl, slice));
+               break;
+            default:
+               xassert(close != close);
+         }
+      }
+      get_token(mpl /* ) | ] */);
+      return slice;
+}
+
+/*----------------------------------------------------------------------
+-- select_set - select set to saturate it with elemental sets.
+--
+-- This routine selects set to saturate it with elemental sets provided
+-- in the data section. */
+
+SET *select_set
+(     MPL *mpl,
+      char *name              /* not changed */
+)
+{     SET *set;
+      AVLNODE *node;
+      xassert(name != NULL);
+      node = avl_find_node(mpl->tree, name);
+      if (node == NULL || avl_get_node_type(node) != A_SET)
+         error(mpl, "%s not a set", name);
+      set = (SET *)avl_get_node_link(node);
+      if (set->assign != NULL || set->gadget != NULL)
+         error(mpl, "%s needs no data", name);
+      set->data = 1;
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- simple_format - read set data block in simple format.
+--
+-- This routine reads set data block using the syntax:
+--
+-- <simple format> ::= <symbol> , <symbol> , ... , <symbol>
+--
+-- where <symbols> are used to construct a complete n-tuple, which is
+-- included in elemental set assigned to the set member. Commae between
+-- symbols are optional and may be omitted anywhere.
+--
+-- Number of components in the slice must be the same as dimension of
+-- n-tuples in elemental sets assigned to the set members. To construct
+-- complete n-tuple the routine replaces null positions in the slice by
+-- corresponding <symbols>.
+--
+-- If the slice contains at least one null position, the current token
+-- must be symbol. Otherwise, the routine reads no symbols to construct
+-- the n-tuple, so the current token is not checked. */
+
+void simple_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice            /* not changed */
+)
+{     TUPLE *tuple;
+      SLICE *temp;
+      SYMBOL *sym, *with = NULL;
+      xassert(set != NULL);
+      xassert(memb != NULL);
+      xassert(slice != NULL);
+      xassert(set->dimen == slice_dimen(mpl, slice));
+      xassert(memb->value.set->dim == set->dimen);
+      if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl));
+      /* read symbols and construct complete n-tuple */
+      tuple = create_tuple(mpl);
+      for (temp = slice; temp != NULL; temp = temp->next)
+      {  if (temp->sym == NULL)
+         {  /* substitution is needed; read symbol */
+            if (!is_symbol(mpl))
+            {  int lack = slice_arity(mpl, temp);
+               /* with cannot be null due to assertion above */
+               xassert(with != NULL);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, with));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, with));
+            }
+            sym = read_symbol(mpl);
+            if (with == NULL) with = sym;
+         }
+         else
+         {  /* copy symbol from the slice */
+            sym = copy_symbol(mpl, temp->sym);
+         }
+         /* append the symbol to the n-tuple */
+         tuple = expand_tuple(mpl, tuple, sym);
+         /* skip optional comma *between* <symbols> */
+         if (temp->next != NULL && mpl->token == T_COMMA)
+            get_token(mpl /* , */);
+      }
+      /* add constructed n-tuple to elemental set */
+      check_then_add(mpl, memb->value.set, tuple);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- matrix_format - read set data block in matrix format.
+--
+-- This routine reads set data block using the syntax:
+--
+-- <matrix format> ::= <column> <column> ... <column> :=
+--               <row>   +/-      +/-    ...   +/-
+--               <row>   +/-      +/-    ...   +/-
+--                 .  .  .  .  .  .  .  .  .  .  .
+--               <row>   +/-      +/-    ...   +/-
+--
+-- where <rows> are symbols that denote rows of the matrix, <columns>
+-- are symbols that denote columns of the matrix, "+" and "-" indicate
+-- whether corresponding n-tuple needs to be included in the elemental
+-- set or not, respectively.
+--
+-- Number of the slice components must be the same as dimension of the
+-- elemental set. The slice must have two null positions. To construct
+-- complete n-tuple for particular element of the matrix the routine
+-- replaces first null position of the slice by the corresponding <row>
+-- (or <column>, if the flag tr is on) and second null position by the
+-- corresponding <column> (or by <row>, if the flag tr is on). */
+
+void matrix_format
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      MEMBER *memb,           /* modified */
+      SLICE *slice,           /* not changed */
+      int tr
+)
+{     SLICE *list, *col, *temp;
+      TUPLE *tuple;
+      SYMBOL *row;
+      xassert(set != NULL);
+      xassert(memb != NULL);
+      xassert(slice != NULL);
+      xassert(set->dimen == slice_dimen(mpl, slice));
+      xassert(memb->value.set->dim == set->dimen);
+      xassert(slice_arity(mpl, slice) == 2);
+      /* read the matrix heading that contains column symbols (there
+         may be no columns at all) */
+      list = create_slice(mpl);
+      while (mpl->token != T_ASSIGN)
+      {  /* read column symbol and append it to the column list */
+         if (!is_symbol(mpl))
+            error(mpl, "number, symbol, or := missing where expected");
+         list = expand_slice(mpl, list, read_symbol(mpl));
+      }
+      get_token(mpl /* := */);
+      /* read zero or more rows that contain matrix data */
+      while (is_symbol(mpl))
+      {  /* read row symbol (if the matrix has no columns, row symbols
+            are just ignored) */
+         row = read_symbol(mpl);
+         /* read the matrix row accordingly to the column list */
+         for (col = list; col != NULL; col = col->next)
+         {  int which = 0;
+            /* check indicator */
+            if (is_literal(mpl, "+"))
+               ;
+            else if (is_literal(mpl, "-"))
+            {  get_token(mpl /* - */);
+               continue;
+            }
+            else
+            {  int lack = slice_dimen(mpl, col);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, row));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, row));
+            }
+            /* construct complete n-tuple */
+            tuple = create_tuple(mpl);
+            for (temp = slice; temp != NULL; temp = temp->next)
+            {  if (temp->sym == NULL)
+               {  /* substitution is needed */
+                  switch (++which)
+                  {  case 1:
+                        /* substitute in the first null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? col->sym : row));
+                        break;
+                     case 2:
+                        /* substitute in the second null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? row : col->sym));
+                        break;
+                     default:
+                        xassert(which != which);
+                  }
+               }
+               else
+               {  /* copy symbol from the slice */
+                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                     temp->sym));
+               }
+            }
+            xassert(which == 2);
+            /* add constructed n-tuple to elemental set */
+            check_then_add(mpl, memb->value.set, tuple);
+            get_token(mpl /* + */);
+         }
+         /* delete the row symbol */
+         delete_symbol(mpl, row);
+      }
+      /* delete the column list */
+      delete_slice(mpl, list);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- set_data - read set data.
+--
+-- This routine reads set data using the syntax:
+--
+-- <set data> ::= set <set name> <assignments> ;
+-- <set data> ::= set <set name> [ <symbol list> ] <assignments> ;
+-- <set name> ::= <symbolic name>
+-- <assignments> ::= <empty>
+-- <assignments> ::= <assignments> , :=
+-- <assignments> ::= <assignments> , ( <symbol list> )
+-- <assignments> ::= <assignments> , <simple format>
+-- <assignments> ::= <assignments> , : <matrix format>
+-- <assignments> ::= <assignments> , (tr) <matrix format>
+-- <assignments> ::= <assignments> , (tr) : <matrix format>
+--
+-- Commae in <assignments> are optional and may be omitted anywhere. */
+
+void set_data(MPL *mpl)
+{     SET *set;
+      TUPLE *tuple;
+      MEMBER *memb;
+      SLICE *slice;
+      int tr = 0;
+      xassert(is_literal(mpl, "set"));
+      get_token(mpl /* set */);
+      /* symbolic name of set must follows the keyword 'set' */
+      if (!is_symbol(mpl))
+         error(mpl, "set name missing where expected");
+      /* select the set to saturate it with data */
+      set = select_set(mpl, mpl->image);
+      get_token(mpl /* <symbolic name> */);
+      /* read optional subscript list, which identifies member of the
+         set to be read */
+      tuple = create_tuple(mpl);
+      if (mpl->token == T_LBRACKET)
+      {  /* subscript list is specified */
+         if (set->dim == 0)
+            error(mpl, "%s cannot be subscripted", set->name);
+         get_token(mpl /* [ */);
+         /* read symbols and construct subscript list */
+         for (;;)
+         {  if (!is_symbol(mpl))
+               error(mpl, "number or symbol missing where expected");
+            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
+            if (mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+            else if (mpl->token == T_RBRACKET)
+               break;
+            else
+               error(mpl, "syntax error in subscript list");
+         }
+         if (set->dim != tuple_dimen(mpl, tuple))
+            error(mpl, "%s must have %d subscript%s rather than %d",
+               set->name, set->dim, set->dim == 1 ? "" : "s",
+               tuple_dimen(mpl, tuple));
+         get_token(mpl /* ] */);
+      }
+      else
+      {  /* subscript list is not specified */
+         if (set->dim != 0)
+            error(mpl, "%s must be subscripted", set->name);
+      }
+      /* there must be no member with the same subscript list */
+      if (find_member(mpl, set->array, tuple) != NULL)
+         error(mpl, "%s%s already defined",
+            set->name, format_tuple(mpl, '[', tuple));
+      /* add new member to the set and assign it empty elemental set */
+      memb = add_member(mpl, set->array, tuple);
+      memb->value.set = create_elemset(mpl, set->dimen);
+      /* create an initial fake slice of all asterisks */
+      slice = fake_slice(mpl, set->dimen);
+      /* read zero or more data assignments */
+      for (;;)
+      {  /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* process assignment element */
+         if (mpl->token == T_ASSIGN)
+         {  /* assignment ligature is non-significant element */
+            get_token(mpl /* := */);
+         }
+         else if (mpl->token == T_LEFT)
+         {  /* left parenthesis begins either new slice or "transpose"
+               indicator */
+            int is_tr;
+            get_token(mpl /* ( */);
+            is_tr = is_literal(mpl, "tr");
+            unget_token(mpl /* ( */);
+            if (is_tr) goto left;
+            /* delete the current slice and read new one */
+            delete_slice(mpl, slice);
+            slice = read_slice(mpl, set->name, set->dimen);
+            /* each new slice resets the "transpose" indicator */
+            tr = 0;
+            /* if the new slice is 0-ary, formally there is one 0-tuple
+               (in the simple format) that follows it */
+            if (slice_arity(mpl, slice) == 0)
+               simple_format(mpl, set, memb, slice);
+         }
+         else if (is_symbol(mpl))
+         {  /* number or symbol begins data in the simple format */
+            simple_format(mpl, set, memb, slice);
+         }
+         else if (mpl->token == T_COLON)
+         {  /* colon begins data in the matrix format */
+            if (slice_arity(mpl, slice) != 2)
+err1:          error(mpl, "slice currently used must specify 2 asterisk"
+                  "s, not %d", slice_arity(mpl, slice));
+            get_token(mpl /* : */);
+            /* read elemental set data in the matrix format */
+            matrix_format(mpl, set, memb, slice, tr);
+         }
+         else if (mpl->token == T_LEFT)
+left:    {  /* left parenthesis begins the "transpose" indicator, which
+               is followed by data in the matrix format */
+            get_token(mpl /* ( */);
+            if (!is_literal(mpl, "tr"))
+err2:          error(mpl, "transpose indicator (tr) incomplete");
+            if (slice_arity(mpl, slice) != 2) goto err1;
+            get_token(mpl /* tr */);
+            if (mpl->token != T_RIGHT) goto err2;
+            get_token(mpl /* ) */);
+            /* in this case the colon is optional */
+            if (mpl->token == T_COLON) get_token(mpl /* : */);
+            /* set the "transpose" indicator */
+            tr = 1;
+            /* read elemental set data in the matrix format */
+            matrix_format(mpl, set, memb, slice, tr);
+         }
+         else if (mpl->token == T_SEMICOLON)
+         {  /* semicolon terminates the data block */
+            get_token(mpl /* ; */);
+            break;
+         }
+         else
+            error(mpl, "syntax error in set data block");
+      }
+      /* delete the current slice */
+      delete_slice(mpl, slice);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- select_parameter - select parameter to saturate it with data.
+--
+-- This routine selects parameter to saturate it with data provided in
+-- the data section. */
+
+PARAMETER *select_parameter
+(     MPL *mpl,
+      char *name              /* not changed */
+)
+{     PARAMETER *par;
+      AVLNODE *node;
+      xassert(name != NULL);
+      node = avl_find_node(mpl->tree, name);
+      if (node == NULL || avl_get_node_type(node) != A_PARAMETER)
+         error(mpl, "%s not a parameter", name);
+      par = (PARAMETER *)avl_get_node_link(node);
+      if (par->assign != NULL)
+         error(mpl, "%s needs no data", name);
+      if (par->data)
+         error(mpl, "%s already provided with data", name);
+      par->data = 1;
+      return par;
+}
+
+/*----------------------------------------------------------------------
+-- set_default - set default parameter value.
+--
+-- This routine sets default value for specified parameter. */
+
+void set_default
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SYMBOL *altval          /* destroyed */
+)
+{     xassert(par != NULL);
+      xassert(altval != NULL);
+      if (par->option != NULL)
+         error(mpl, "default value for %s already specified in model se"
+            "ction", par->name);
+      xassert(par->defval == NULL);
+      par->defval = altval;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- read_value - read value and assign it to parameter member.
+--
+-- This routine reads numeric or symbolic value from the input stream
+-- and assigns to new parameter member specified by its n-tuple, which
+-- (the member) is created and added to the parameter array. */
+
+MEMBER *read_value
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(par != NULL);
+      xassert(is_symbol(mpl));
+      /* there must be no member with the same n-tuple */
+      if (find_member(mpl, par->array, tuple) != NULL)
+         error(mpl, "%s%s already defined",
+            par->name, format_tuple(mpl, '[', tuple));
+      /* create new parameter member with given n-tuple */
+      memb = add_member(mpl, par->array, tuple);
+      /* read value and assigns it to the new parameter member */
+      switch (par->type)
+      {  case A_NUMERIC:
+         case A_INTEGER:
+         case A_BINARY:
+            if (!is_number(mpl))
+               error(mpl, "%s requires numeric data", par->name);
+            memb->value.num = read_number(mpl);
+            break;
+         case A_SYMBOLIC:
+            memb->value.sym = read_symbol(mpl);
+            break;
+         default:
+            xassert(par != par);
+      }
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- plain_format - read parameter data block in plain format.
+--
+-- This routine reads parameter data block using the syntax:
+--
+-- <plain format> ::= <symbol> , <symbol> , ... , <symbol> , <value>
+--
+-- where <symbols> are used to determine a complete subscript list for
+-- parameter member, <value> is a numeric or symbolic value assigned to
+-- the parameter member. Commae between data items are optional and may
+-- be omitted anywhere.
+--
+-- Number of components in the slice must be the same as dimension of
+-- the parameter. To construct the complete subscript list the routine
+-- replaces null positions in the slice by corresponding <symbols>. */
+
+void plain_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice            /* not changed */
+)
+{     TUPLE *tuple;
+      SLICE *temp;
+      SYMBOL *sym, *with = NULL;
+      xassert(par != NULL);
+      xassert(par->dim == slice_dimen(mpl, slice));
+      xassert(is_symbol(mpl));
+      /* read symbols and construct complete subscript list */
+      tuple = create_tuple(mpl);
+      for (temp = slice; temp != NULL; temp = temp->next)
+      {  if (temp->sym == NULL)
+         {  /* substitution is needed; read symbol */
+            if (!is_symbol(mpl))
+            {  int lack = slice_arity(mpl, temp) + 1;
+               xassert(with != NULL);
+               xassert(lack > 1);
+               error(mpl, "%d items missing in data group beginning wit"
+                  "h %s", lack, format_symbol(mpl, with));
+            }
+            sym = read_symbol(mpl);
+            if (with == NULL) with = sym;
+         }
+         else
+         {  /* copy symbol from the slice */
+            sym = copy_symbol(mpl, temp->sym);
+         }
+         /* append the symbol to the subscript list */
+         tuple = expand_tuple(mpl, tuple, sym);
+         /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      }
+      /* read value and assign it to new parameter member */
+      if (!is_symbol(mpl))
+      {  xassert(with != NULL);
+         error(mpl, "one item missing in data group beginning with %s",
+            format_symbol(mpl, with));
+      }
+      read_value(mpl, par, tuple);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- tabular_format - read parameter data block in tabular format.
+--
+-- This routine reads parameter data block using the syntax:
+--
+-- <tabular format> ::= <column> <column> ... <column> :=
+--                <row> <value>  <value>  ... <value>
+--                <row> <value>  <value>  ... <value>
+--                  .  .  .  .  .  .  .  .  .  .  .
+--                <row> <value>  <value>  ... <value>
+--
+-- where <rows> are symbols that denote rows of the table, <columns>
+-- are symbols that denote columns of the table, <values> are numeric
+-- or symbolic values assigned to the corresponding parameter members.
+-- If <value> is specified as single point, no value is provided.
+--
+-- Number of components in the slice must be the same as dimension of
+-- the parameter. The slice must have two null positions. To construct
+-- complete subscript list for particular <value> the routine replaces
+-- the first null position of the slice by the corresponding <row> (or
+-- <column>, if the flag tr is on) and the second null position by the
+-- corresponding <column> (or by <row>, if the flag tr is on). */
+
+void tabular_format
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      SLICE *slice,           /* not changed */
+      int tr
+)
+{     SLICE *list, *col, *temp;
+      TUPLE *tuple;
+      SYMBOL *row;
+      xassert(par != NULL);
+      xassert(par->dim == slice_dimen(mpl, slice));
+      xassert(slice_arity(mpl, slice) == 2);
+      /* read the table heading that contains column symbols (the table
+         may have no columns) */
+      list = create_slice(mpl);
+      while (mpl->token != T_ASSIGN)
+      {  /* read column symbol and append it to the column list */
+         if (!is_symbol(mpl))
+            error(mpl, "number, symbol, or := missing where expected");
+         list = expand_slice(mpl, list, read_symbol(mpl));
+      }
+      get_token(mpl /* := */);
+      /* read zero or more rows that contain tabular data */
+      while (is_symbol(mpl))
+      {  /* read row symbol (if the table has no columns, these symbols
+            are just ignored) */
+         row = read_symbol(mpl);
+         /* read values accordingly to the column list */
+         for (col = list; col != NULL; col = col->next)
+         {  int which = 0;
+            /* if the token is single point, no value is provided */
+            if (is_literal(mpl, "."))
+            {  get_token(mpl /* . */);
+               continue;
+            }
+            /* construct complete subscript list */
+            tuple = create_tuple(mpl);
+            for (temp = slice; temp != NULL; temp = temp->next)
+            {  if (temp->sym == NULL)
+               {  /* substitution is needed */
+                  switch (++which)
+                  {  case 1:
+                        /* substitute in the first null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? col->sym : row));
+                        break;
+                     case 2:
+                        /* substitute in the second null position */
+                        tuple = expand_tuple(mpl, tuple,
+                           copy_symbol(mpl, tr ? row : col->sym));
+                        break;
+                     default:
+                        xassert(which != which);
+                  }
+               }
+               else
+               {  /* copy symbol from the slice */
+                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                     temp->sym));
+               }
+            }
+            xassert(which == 2);
+            /* read value and assign it to new parameter member */
+            if (!is_symbol(mpl))
+            {  int lack = slice_dimen(mpl, col);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, row));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, row));
+            }
+            read_value(mpl, par, tuple);
+         }
+         /* delete the row symbol */
+         delete_symbol(mpl, row);
+      }
+      /* delete the column list */
+      delete_slice(mpl, list);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- tabbing_format - read parameter data block in tabbing format.
+--
+-- This routine reads parameter data block using the syntax:
+--
+-- <tabbing format> ::=  <prefix> <name>  , ... , <name>  , := ,
+--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
+--    <symbol> , ... , <symbol> , <value> , ... , <value> ,
+--     .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .
+--    <symbol> , ... , <symbol> , <value> , ... , <value>
+-- <prefix> ::= <empty>
+-- <prefix> ::= <set name> :
+--
+-- where <names> are names of parameters (all the parameters must be
+-- subscripted and have identical dimensions), <symbols> are symbols
+-- used to define subscripts of parameter members, <values> are numeric
+-- or symbolic values assigned to the corresponding parameter members.
+-- Optional <prefix> may specify a simple set, in which case n-tuples
+-- built of <symbols> for each row of the data table (i.e. subscripts
+-- of parameter members) are added to the specified set. Commae between
+-- data items are optional and may be omitted anywhere.
+--
+-- If the parameter altval is not NULL, it specifies a default value
+-- provided for all the parameters specified in the data block.  */
+
+void tabbing_format
+(     MPL *mpl,
+      SYMBOL *altval          /* not changed */
+)
+{     SET *set = NULL;
+      PARAMETER *par;
+      SLICE *list, *col;
+      TUPLE *tuple;
+      int next_token, j, dim = 0;
+      char *last_name = NULL;
+      /* read the optional <prefix> */
+      if (is_symbol(mpl))
+      {  get_token(mpl /* <symbol> */);
+         next_token = mpl->token;
+         unget_token(mpl /* <symbol> */);
+         if (next_token == T_COLON)
+         {  /* select the set to saturate it with data */
+            set = select_set(mpl, mpl->image);
+            /* the set must be simple (i.e. not set of sets) */
+            if (set->dim != 0)
+               error(mpl, "%s must be a simple set", set->name);
+            /* and must not be defined yet */
+            if (set->array->head != NULL)
+               error(mpl, "%s already defined", set->name);
+            /* add new (the only) member to the set and assign it empty
+               elemental set */
+            add_member(mpl, set->array, NULL)->value.set =
+               create_elemset(mpl, set->dimen);
+            last_name = set->name, dim = set->dimen;
+            get_token(mpl /* <symbol> */);
+            xassert(mpl->token == T_COLON);
+            get_token(mpl /* : */);
+         }
+      }
+      /* read the table heading that contains parameter names */
+      list = create_slice(mpl);
+      while (mpl->token != T_ASSIGN)
+      {  /* there must be symbolic name of parameter */
+         if (!is_symbol(mpl))
+            error(mpl, "parameter name or := missing where expected");
+         /* select the parameter to saturate it with data */
+         par = select_parameter(mpl, mpl->image);
+         /* the parameter must be subscripted */
+         if (par->dim == 0)
+            error(mpl, "%s not a subscripted parameter", mpl->image);
+         /* the set (if specified) and all the parameters in the data
+            block must have identical dimension */
+         if (dim != 0 && par->dim != dim)
+         {  xassert(last_name != NULL);
+            error(mpl, "%s has dimension %d while %s has dimension %d",
+               last_name, dim, par->name, par->dim);
+         }
+         /* set default value for the parameter (if specified) */
+         if (altval != NULL)
+            set_default(mpl, par, copy_symbol(mpl, altval));
+         /* append the parameter to the column list */
+         list = expand_slice(mpl, list, (SYMBOL *)par);
+         last_name = par->name, dim = par->dim;
+         get_token(mpl /* <symbol> */);
+         /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      }
+      if (slice_dimen(mpl, list) == 0)
+         error(mpl, "at least one parameter name required");
+      get_token(mpl /* := */);
+      /* skip optional comma */
+      if (mpl->token == T_COMMA) get_token(mpl /* , */);
+      /* read rows that contain tabbing data */
+      while (is_symbol(mpl))
+      {  /* read subscript list */
+         tuple = create_tuple(mpl);
+         for (j = 1; j <= dim; j++)
+         {  /* read j-th subscript */
+            if (!is_symbol(mpl))
+            {  int lack = slice_dimen(mpl, list) + dim - j + 1;
+               xassert(tuple != NULL);
+               xassert(lack > 1);
+               error(mpl, "%d items missing in data group beginning wit"
+                  "h %s", lack, format_symbol(mpl, tuple->sym));
+            }
+            /* read and append j-th subscript to the n-tuple */
+            tuple = expand_tuple(mpl, tuple, read_symbol(mpl));
+            /* skip optional comma *between* <symbols> */
+            if (j < dim && mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+         }
+         /* if the set is specified, add to it new n-tuple, which is a
+            copy of the subscript list just read */
+         if (set != NULL)
+            check_then_add(mpl, set->array->head->value.set,
+               copy_tuple(mpl, tuple));
+         /* skip optional comma between <symbol> and <value> */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* read values accordingly to the column list */
+         for (col = list; col != NULL; col = col->next)
+         {  /* if the token is single point, no value is provided */
+            if (is_literal(mpl, "."))
+            {  get_token(mpl /* . */);
+               continue;
+            }
+            /* read value and assign it to new parameter member */
+            if (!is_symbol(mpl))
+            {  int lack = slice_dimen(mpl, col);
+               xassert(tuple != NULL);
+               if (lack == 1)
+                  error(mpl, "one item missing in data group beginning "
+                     "with %s", format_symbol(mpl, tuple->sym));
+               else
+                  error(mpl, "%d items missing in data group beginning "
+                     "with %s", lack, format_symbol(mpl, tuple->sym));
+            }
+            read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl,
+               tuple));
+            /* skip optional comma preceding the next value */
+            if (col->next != NULL && mpl->token == T_COMMA)
+               get_token(mpl /* , */);
+         }
+         /* delete the original subscript list */
+         delete_tuple(mpl, tuple);
+         /* skip optional comma (only if there is next data group) */
+         if (mpl->token == T_COMMA)
+         {  get_token(mpl /* , */);
+            if (!is_symbol(mpl)) unget_token(mpl /* , */);
+         }
+      }
+      /* delete the column list (it contains parameters, not symbols,
+         so nullify it before) */
+      for (col = list; col != NULL; col = col->next) col->sym = NULL;
+      delete_slice(mpl, list);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- parameter_data - read parameter data.
+--
+-- This routine reads parameter data using the syntax:
+--
+-- <parameter data> ::= param <default value> : <tabbing format> ;
+-- <parameter data> ::= param <parameter name> <default value>
+--                      <assignments> ;
+-- <parameter name> ::= <symbolic name>
+-- <default value> ::= <empty>
+-- <default value> ::= default <symbol>
+-- <assignments> ::= <empty>
+-- <assignments> ::= <assignments> , :=
+-- <assignments> ::= <assignments> , [ <symbol list> ]
+-- <assignments> ::= <assignments> , <plain format>
+-- <assignemnts> ::= <assignments> , : <tabular format>
+-- <assignments> ::= <assignments> , (tr) <tabular format>
+-- <assignments> ::= <assignments> , (tr) : <tabular format>
+--
+-- Commae in <assignments> are optional and may be omitted anywhere. */
+
+void parameter_data(MPL *mpl)
+{     PARAMETER *par;
+      SYMBOL *altval = NULL;
+      SLICE *slice;
+      int tr = 0;
+      xassert(is_literal(mpl, "param"));
+      get_token(mpl /* param */);
+      /* read optional default value */
+      if (is_literal(mpl, "default"))
+      {  get_token(mpl /* default */);
+         if (!is_symbol(mpl))
+            error(mpl, "default value missing where expected");
+         altval = read_symbol(mpl);
+         /* if the default value follows the keyword 'param', the next
+            token must be only the colon */
+         if (mpl->token != T_COLON)
+            error(mpl, "colon missing where expected");
+      }
+      /* being used after the keyword 'param' or the optional default
+         value the colon begins data in the tabbing format */
+      if (mpl->token == T_COLON)
+      {  get_token(mpl /* : */);
+         /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* read parameter data in the tabbing format */
+         tabbing_format(mpl, altval);
+         /* on reading data in the tabbing format the default value is
+            always copied, so delete the original symbol */
+         if (altval != NULL) delete_symbol(mpl, altval);
+         /* the next token must be only semicolon */
+         if (mpl->token != T_SEMICOLON)
+            error(mpl, "symbol, number, or semicolon missing where expe"
+               "cted");
+         get_token(mpl /* ; */);
+         goto done;
+      }
+      /* in other cases there must be symbolic name of parameter, which
+         follows the keyword 'param' */
+      if (!is_symbol(mpl))
+         error(mpl, "parameter name missing where expected");
+      /* select the parameter to saturate it with data */
+      par = select_parameter(mpl, mpl->image);
+      get_token(mpl /* <symbol> */);
+      /* read optional default value */
+      if (is_literal(mpl, "default"))
+      {  get_token(mpl /* default */);
+         if (!is_symbol(mpl))
+            error(mpl, "default value missing where expected");
+         altval = read_symbol(mpl);
+         /* set default value for the parameter */
+         set_default(mpl, par, altval);
+      }
+      /* create initial fake slice of all asterisks */
+      slice = fake_slice(mpl, par->dim);
+      /* read zero or more data assignments */
+      for (;;)
+      {  /* skip optional comma */
+         if (mpl->token == T_COMMA) get_token(mpl /* , */);
+         /* process current assignment */
+         if (mpl->token == T_ASSIGN)
+         {  /* assignment ligature is non-significant element */
+            get_token(mpl /* := */);
+         }
+         else if (mpl->token == T_LBRACKET)
+         {  /* left bracket begins new slice; delete the current slice
+               and read new one */
+            delete_slice(mpl, slice);
+            slice = read_slice(mpl, par->name, par->dim);
+            /* each new slice resets the "transpose" indicator */
+            tr = 0;
+         }
+         else if (is_symbol(mpl))
+         {  /* number or symbol begins data in the plain format */
+            plain_format(mpl, par, slice);
+         }
+         else if (mpl->token == T_COLON)
+         {  /* colon begins data in the tabular format */
+            if (par->dim == 0)
+err1:          error(mpl, "%s not a subscripted parameter",
+                  par->name);
+            if (slice_arity(mpl, slice) != 2)
+err2:          error(mpl, "slice currently used must specify 2 asterisk"
+                  "s, not %d", slice_arity(mpl, slice));
+            get_token(mpl /* : */);
+            /* read parameter data in the tabular format */
+            tabular_format(mpl, par, slice, tr);
+         }
+         else if (mpl->token == T_LEFT)
+         {  /* left parenthesis begins the "transpose" indicator, which
+               is followed by data in the tabular format */
+            get_token(mpl /* ( */);
+            if (!is_literal(mpl, "tr"))
+err3:          error(mpl, "transpose indicator (tr) incomplete");
+            if (par->dim == 0) goto err1;
+            if (slice_arity(mpl, slice) != 2) goto err2;
+            get_token(mpl /* tr */);
+            if (mpl->token != T_RIGHT) goto err3;
+            get_token(mpl /* ) */);
+            /* in this case the colon is optional */
+            if (mpl->token == T_COLON) get_token(mpl /* : */);
+            /* set the "transpose" indicator */
+            tr = 1;
+            /* read parameter data in the tabular format */
+            tabular_format(mpl, par, slice, tr);
+         }
+         else if (mpl->token == T_SEMICOLON)
+         {  /* semicolon terminates the data block */
+            get_token(mpl /* ; */);
+            break;
+         }
+         else
+            error(mpl, "syntax error in parameter data block");
+      }
+      /* delete the current slice */
+      delete_slice(mpl, slice);
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- data_section - read data section.
+--
+-- This routine reads data section using the syntax:
+--
+-- <data section> ::= <empty>
+-- <data section> ::= <data section> <data block> ;
+-- <data block> ::= <set data>
+-- <data block> ::= <parameter data>
+--
+-- Reading data section is terminated by either the keyword 'end' or
+-- the end of file. */
+
+void data_section(MPL *mpl)
+{     while (!(mpl->token == T_EOF || is_literal(mpl, "end")))
+      {  if (is_literal(mpl, "set"))
+            set_data(mpl);
+         else if (is_literal(mpl, "param"))
+            parameter_data(mpl);
+         else
+            error(mpl, "syntax error in data section");
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpmpl03.c
===================================================================
--- deps/glpk/src/glpmpl03.c	(revision 9)
+++ deps/glpk/src/glpmpl03.c	(revision 9)
@@ -0,0 +1,6078 @@
+/* glpmpl03.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glpmpl.h"
+
+/**********************************************************************/
+/* * *                   FLOATING-POINT NUMBERS                   * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- fp_add - floating-point addition.
+--
+-- This routine computes the sum x + y. */
+
+double fp_add(MPL *mpl, double x, double y)
+{     if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y ||
+          x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y)
+         error(mpl, "%.*g + %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x + y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_sub - floating-point subtraction.
+--
+-- This routine computes the difference x - y. */
+
+double fp_sub(MPL *mpl, double x, double y)
+{     if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y ||
+          x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y)
+         error(mpl, "%.*g - %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x - y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_less - floating-point non-negative subtraction.
+--
+-- This routine computes the non-negative difference max(0, x - y). */
+
+double fp_less(MPL *mpl, double x, double y)
+{     if (x < y) return 0.0;
+      if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y)
+         error(mpl, "%.*g less %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x - y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_mul - floating-point multiplication.
+--
+-- This routine computes the product x * y. */
+
+double fp_mul(MPL *mpl, double x, double y)
+{     if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y))
+         error(mpl, "%.*g * %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x * y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_div - floating-point division.
+--
+-- This routine computes the quotient x / y. */
+
+double fp_div(MPL *mpl, double x, double y)
+{     if (fabs(y) < DBL_MIN)
+         error(mpl, "%.*g / %.*g; floating-point zero divide",
+            DBL_DIG, x, DBL_DIG, y);
+      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
+         error(mpl, "%.*g / %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      return x / y;
+}
+
+/*----------------------------------------------------------------------
+-- fp_idiv - floating-point quotient of exact division.
+--
+-- This routine computes the quotient of exact division x div y. */
+
+double fp_idiv(MPL *mpl, double x, double y)
+{     if (fabs(y) < DBL_MIN)
+         error(mpl, "%.*g div %.*g; floating-point zero divide",
+            DBL_DIG, x, DBL_DIG, y);
+      if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y))
+         error(mpl, "%.*g div %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      x /= y;
+      return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0;
+}
+
+/*----------------------------------------------------------------------
+-- fp_mod - floating-point remainder of exact division.
+--
+-- This routine computes the remainder of exact division x mod y.
+--
+-- NOTE: By definition x mod y = x - y * floor(x / y). */
+
+double fp_mod(MPL *mpl, double x, double y)
+{     double r;
+      xassert(mpl == mpl);
+      if (x == 0.0)
+         r = 0.0;
+      else if (y == 0.0)
+         r = x;
+      else
+      {  r = fmod(fabs(x), fabs(y));
+         if (r != 0.0)
+         {  if (x < 0.0) r = - r;
+            if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y;
+         }
+      }
+      return r;
+}
+
+/*----------------------------------------------------------------------
+-- fp_power - floating-point exponentiation (raise to power).
+--
+-- This routine computes the exponentiation x ** y. */
+
+double fp_power(MPL *mpl, double x, double y)
+{     double r;
+      if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y))
+         error(mpl, "%.*g ** %.*g; result undefined",
+            DBL_DIG, x, DBL_DIG, y);
+      if (x == 0.0) goto eval;
+      if (fabs(x) > 1.0 && y > +1.0 &&
+            +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y ||
+          fabs(x) < 1.0 && y < -1.0 &&
+            +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y)
+         error(mpl, "%.*g ** %.*g; floating-point overflow",
+            DBL_DIG, x, DBL_DIG, y);
+      if (fabs(x) > 1.0 && y < -1.0 &&
+            -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y ||
+          fabs(x) < 1.0 && y > +1.0 &&
+            -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y)
+         r = 0.0;
+      else
+eval:    r = pow(x, y);
+      return r;
+}
+
+/*----------------------------------------------------------------------
+-- fp_exp - floating-point base-e exponential.
+--
+-- This routine computes the base-e exponential e ** x. */
+
+double fp_exp(MPL *mpl, double x)
+{     if (x > 0.999 * log(DBL_MAX))
+         error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x);
+      return exp(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_log - floating-point natural logarithm.
+--
+-- This routine computes the natural logarithm log x. */
+
+double fp_log(MPL *mpl, double x)
+{     if (x <= 0.0)
+         error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x);
+      return log(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_log10 - floating-point common (decimal) logarithm.
+--
+-- This routine computes the common (decimal) logarithm lg x. */
+
+double fp_log10(MPL *mpl, double x)
+{     if (x <= 0.0)
+         error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x);
+      return log10(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_sqrt - floating-point square root.
+--
+-- This routine computes the square root x ** 0.5. */
+
+double fp_sqrt(MPL *mpl, double x)
+{     if (x < 0.0)
+         error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x);
+      return sqrt(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_sin - floating-point trigonometric sine.
+--
+-- This routine computes the trigonometric sine sin(x). */
+
+double fp_sin(MPL *mpl, double x)
+{     if (!(-1e6 <= x && x <= +1e6))
+         error(mpl, "sin(%.*g); argument too large", DBL_DIG, x);
+      return sin(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_cos - floating-point trigonometric cosine.
+--
+-- This routine computes the trigonometric cosine cos(x). */
+
+double fp_cos(MPL *mpl, double x)
+{     if (!(-1e6 <= x && x <= +1e6))
+         error(mpl, "cos(%.*g); argument too large", DBL_DIG, x);
+      return cos(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_atan - floating-point trigonometric arctangent.
+--
+-- This routine computes the trigonometric arctangent atan(x). */
+
+double fp_atan(MPL *mpl, double x)
+{     xassert(mpl == mpl);
+      return atan(x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_atan2 - floating-point trigonometric arctangent.
+--
+-- This routine computes the trigonometric arctangent atan(y / x). */
+
+double fp_atan2(MPL *mpl, double y, double x)
+{     xassert(mpl == mpl);
+      return atan2(y, x);
+}
+
+/*----------------------------------------------------------------------
+-- fp_round - round floating-point value to n fractional digits.
+--
+-- This routine rounds given floating-point value x to n fractional
+-- digits with the formula:
+--
+--    round(x, n) = floor(x * 10^n + 0.5) / 10^n.
+--
+-- The parameter n is assumed to be integer. */
+
+double fp_round(MPL *mpl, double x, double n)
+{     double ten_to_n;
+      if (n != floor(n))
+         error(mpl, "round(%.*g, %.*g); non-integer second argument",
+            DBL_DIG, x, DBL_DIG, n);
+      if (n <= DBL_DIG + 2)
+      {  ten_to_n = pow(10.0, n);
+         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
+         {  x = floor(x * ten_to_n + 0.5);
+            if (x != 0.0) x /= ten_to_n;
+         }
+      }
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- fp_trunc - truncate floating-point value to n fractional digits.
+--
+-- This routine truncates given floating-point value x to n fractional
+-- digits with the formula:
+--
+--                  ( floor(x * 10^n) / 10^n,  if x >= 0
+--    trunc(x, n) = <
+--                  ( ceil(x * 10^n) / 10^n,   if x < 0
+--
+-- The parameter n is assumed to be integer. */
+
+double fp_trunc(MPL *mpl, double x, double n)
+{     double ten_to_n;
+      if (n != floor(n))
+         error(mpl, "trunc(%.*g, %.*g); non-integer second argument",
+            DBL_DIG, x, DBL_DIG, n);
+      if (n <= DBL_DIG + 2)
+      {  ten_to_n = pow(10.0, n);
+         if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n)
+         {  x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n));
+            if (x != 0.0) x /= ten_to_n;
+         }
+      }
+      return x;
+}
+
+/**********************************************************************/
+/* * *              PSEUDO-RANDOM NUMBER GENERATORS               * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- fp_irand224 - pseudo-random integer in the range [0, 2^24).
+--
+-- This routine returns a next pseudo-random integer (converted to
+-- floating-point) which is uniformly distributed between 0 and 2^24-1,
+-- inclusive. */
+
+#define two_to_the_24 0x1000000
+
+double fp_irand224(MPL *mpl)
+{     return
+         (double)rng_unif_rand(mpl->rand, two_to_the_24);
+}
+
+/*----------------------------------------------------------------------
+-- fp_uniform01 - pseudo-random number in the range [0, 1).
+--
+-- This routine returns a next pseudo-random number which is uniformly
+-- distributed in the range [0, 1). */
+
+#define two_to_the_31 ((unsigned int)0x80000000)
+
+double fp_uniform01(MPL *mpl)
+{     return
+         (double)rng_next_rand(mpl->rand) / (double)two_to_the_31;
+}
+
+/*----------------------------------------------------------------------
+-- fp_uniform - pseudo-random number in the range [a, b).
+--
+-- This routine returns a next pseudo-random number which is uniformly
+-- distributed in the range [a, b). */
+
+double fp_uniform(MPL *mpl, double a, double b)
+{     double x;
+      if (a >= b)
+         error(mpl, "Uniform(%.*g, %.*g); invalid range",
+            DBL_DIG, a, DBL_DIG, b);
+      x = fp_uniform01(mpl);
+#if 0
+      x = a * (1.0 - x) + b * x;
+#else
+      x = fp_add(mpl, a * (1.0 - x), b * x);
+#endif
+      return x;
+}
+
+/*----------------------------------------------------------------------
+-- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1.
+--
+-- This routine returns a Gaussian random variate with zero mean and
+-- unit standard deviation. The polar (Box-Mueller) method is used.
+--
+-- This code is a modified version of the routine gsl_ran_gaussian from
+-- the GNU Scientific Library Version 1.0. */
+
+double fp_normal01(MPL *mpl)
+{     double x, y, r2;
+      do
+      {  /* choose x, y in uniform square (-1,-1) to (+1,+1) */
+         x = -1.0 + 2.0 * fp_uniform01(mpl);
+         y = -1.0 + 2.0 * fp_uniform01(mpl);
+         /* see if it is in the unit circle */
+         r2 = x * x + y * y;
+      } while (r2 > 1.0 || r2 == 0.0);
+      /* Box-Muller transform */
+      return y * sqrt(-2.0 * log (r2) / r2);
+}
+
+/*----------------------------------------------------------------------
+-- fp_normal - Gaussian random variate with specified mu and sigma.
+--
+-- This routine returns a Gaussian random variate with mean mu and
+-- standard deviation sigma. */
+
+double fp_normal(MPL *mpl, double mu, double sigma)
+{     double x;
+#if 0
+      x = mu + sigma * fp_normal01(mpl);
+#else
+      x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl)));
+#endif
+      return x;
+}
+
+/**********************************************************************/
+/* * *                SEGMENTED CHARACTER STRINGS                 * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_string - create character string.
+--
+-- This routine creates a segmented character string, which is exactly
+-- equivalent to specified character string. */
+
+STRING *create_string
+(     MPL *mpl,
+      char buf[MAX_LENGTH+1]  /* not changed */
+)
+#if 0
+{     STRING *head, *tail;
+      int i, j;
+      xassert(buf != NULL);
+      xassert(strlen(buf) <= MAX_LENGTH);
+      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
+      for (i = j = 0; ; i++)
+      {  if ((tail->seg[j++] = buf[i]) == '\0') break;
+         if (j == STRSEG_SIZE)
+tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0;
+      }
+      tail->next = NULL;
+      return head;
+}
+#else
+{     STRING *str;
+      xassert(strlen(buf) <= MAX_LENGTH);
+      str = dmp_get_atom(mpl->strings, strlen(buf)+1);
+      strcpy(str, buf);
+      return str;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- copy_string - make copy of character string.
+--
+-- This routine returns an exact copy of segmented character string. */
+
+STRING *copy_string
+(     MPL *mpl,
+      STRING *str             /* not changed */
+)
+#if 0
+{     STRING *head, *tail;
+      xassert(str != NULL);
+      head = tail = dmp_get_atom(mpl->strings, sizeof(STRING));
+      for (; str != NULL; str = str->next)
+      {  memcpy(tail->seg, str->seg, STRSEG_SIZE);
+         if (str->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING)));
+      }
+      tail->next = NULL;
+      return head;
+}
+#else
+{     xassert(mpl == mpl);
+      return create_string(mpl, str);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- compare_strings - compare one character string with another.
+--
+-- This routine compares one segmented character strings with another
+-- and returns the result of comparison as follows:
+--
+-- = 0 - both strings are identical;
+-- < 0 - the first string precedes the second one;
+-- > 0 - the first string follows the second one. */
+
+int compare_strings
+(     MPL *mpl,
+      STRING *str1,           /* not changed */
+      STRING *str2            /* not changed */
+)
+#if 0
+{     int j, c1, c2;
+      xassert(mpl == mpl);
+      for (;; str1 = str1->next, str2 = str2->next)
+      {  xassert(str1 != NULL);
+         xassert(str2 != NULL);
+         for (j = 0; j < STRSEG_SIZE; j++)
+         {  c1 = (unsigned char)str1->seg[j];
+            c2 = (unsigned char)str2->seg[j];
+            if (c1 < c2) return -1;
+            if (c1 > c2) return +1;
+            if (c1 == '\0') goto done;
+         }
+      }
+done: return 0;
+}
+#else
+{     xassert(mpl == mpl);
+      return strcmp(str1, str2);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- fetch_string - extract content of character string.
+--
+-- This routine returns a character string, which is exactly equivalent
+-- to specified segmented character string. */
+
+char *fetch_string
+(     MPL *mpl,
+      STRING *str,            /* not changed */
+      char buf[MAX_LENGTH+1]  /* modified */
+)
+#if 0
+{     int i, j;
+      xassert(mpl == mpl);
+      xassert(buf != NULL);
+      for (i = 0; ; str = str->next)
+      {  xassert(str != NULL);
+         for (j = 0; j < STRSEG_SIZE; j++)
+            if ((buf[i++] = str->seg[j]) == '\0') goto done;
+      }
+done: xassert(strlen(buf) <= MAX_LENGTH);
+      return buf;
+}
+#else
+{     xassert(mpl == mpl);
+      return strcpy(buf, str);
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- delete_string - delete character string.
+--
+-- This routine deletes specified segmented character string. */
+
+void delete_string
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+)
+#if 0
+{     STRING *temp;
+      xassert(str != NULL);
+      while (str != NULL)
+      {  temp = str;
+         str = str->next;
+         dmp_free_atom(mpl->strings, temp, sizeof(STRING));
+      }
+      return;
+}
+#else
+{     dmp_free_atom(mpl->strings, str, strlen(str)+1);
+      return;
+}
+#endif
+
+/**********************************************************************/
+/* * *                          SYMBOLS                           * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_symbol_num - create symbol of numeric type.
+--
+-- This routine creates a symbol, which has a numeric value specified
+-- as floating-point number. */
+
+SYMBOL *create_symbol_num(MPL *mpl, double num)
+{     SYMBOL *sym;
+      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+      sym->num = num;
+      sym->str = NULL;
+      return sym;
+}
+
+/*----------------------------------------------------------------------
+-- create_symbol_str - create symbol of abstract type.
+--
+-- This routine creates a symbol, which has an abstract value specified
+-- as segmented character string. */
+
+SYMBOL *create_symbol_str
+(     MPL *mpl,
+      STRING *str             /* destroyed */
+)
+{     SYMBOL *sym;
+      xassert(str != NULL);
+      sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+      sym->num = 0.0;
+      sym->str = str;
+      return sym;
+}
+
+/*----------------------------------------------------------------------
+-- copy_symbol - make copy of symbol.
+--
+-- This routine returns an exact copy of symbol. */
+
+SYMBOL *copy_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+)
+{     SYMBOL *copy;
+      xassert(sym != NULL);
+      copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL));
+      if (sym->str == NULL)
+      {  copy->num = sym->num;
+         copy->str = NULL;
+      }
+      else
+      {  copy->num = 0.0;
+         copy->str = copy_string(mpl, sym->str);
+      }
+      return copy;
+}
+
+/*----------------------------------------------------------------------
+-- compare_symbols - compare one symbol with another.
+--
+-- This routine compares one symbol with another and returns the result
+-- of comparison as follows:
+--
+-- = 0 - both symbols are identical;
+-- < 0 - the first symbol precedes the second one;
+-- > 0 - the first symbol follows the second one.
+--
+-- Note that the linear order, in which symbols follow each other, is
+-- implementation-dependent. It may be not an alphabetical order. */
+
+int compare_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* not changed */
+      SYMBOL *sym2            /* not changed */
+)
+{     xassert(sym1 != NULL);
+      xassert(sym2 != NULL);
+      /* let all numeric quantities precede all symbolic quantities */
+      if (sym1->str == NULL && sym2->str == NULL)
+      {  if (sym1->num < sym2->num) return -1;
+         if (sym1->num > sym2->num) return +1;
+         return 0;
+      }
+      if (sym1->str == NULL) return -1;
+      if (sym2->str == NULL) return +1;
+      return compare_strings(mpl, sym1->str, sym2->str);
+}
+
+/*----------------------------------------------------------------------
+-- delete_symbol - delete symbol.
+--
+-- This routine deletes specified symbol. */
+
+void delete_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* destroyed */
+)
+{     xassert(sym != NULL);
+      if (sym->str != NULL) delete_string(mpl, sym->str);
+      dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL));
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- format_symbol - format symbol for displaying or printing.
+--
+-- This routine converts specified symbol to a charater string, which
+-- is suitable for displaying or printing.
+--
+-- The resultant string is never longer than 255 characters. If it gets
+-- longer, it is truncated from the right and appended by dots. */
+
+char *format_symbol
+(     MPL *mpl,
+      SYMBOL *sym             /* not changed */
+)
+{     char *buf = mpl->sym_buf;
+      xassert(sym != NULL);
+      if (sym->str == NULL)
+         sprintf(buf, "%.*g", DBL_DIG, sym->num);
+      else
+      {  char str[MAX_LENGTH+1];
+         int quoted, j, len;
+         fetch_string(mpl, sym->str, str);
+         if (!(isalpha((unsigned char)str[0]) || str[0] == '_'))
+            quoted = 1;
+         else
+         {  quoted = 0;
+            for (j = 1; str[j] != '\0'; j++)
+            {  if (!(isalnum((unsigned char)str[j]) ||
+                     strchr("+-._", (unsigned char)str[j]) != NULL))
+               {  quoted = 1;
+                  break;
+               }
+            }
+         }
+#        define safe_append(c) \
+            (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
+         buf[0] = '\0', len = 0;
+         if (quoted) safe_append('\'');
+         for (j = 0; str[j] != '\0'; j++)
+         {  if (quoted && str[j] == '\'') safe_append('\'');
+            safe_append(str[j]);
+         }
+         if (quoted) safe_append('\'');
+#        undef safe_append
+         buf[len] = '\0';
+         if (len == 255) strcpy(buf+252, "...");
+      }
+      xassert(strlen(buf) <= 255);
+      return buf;
+}
+
+/*----------------------------------------------------------------------
+-- concat_symbols - concatenate one symbol with another.
+--
+-- This routine concatenates values of two given symbols and assigns
+-- the resultant character string to a new symbol, which is returned on
+-- exit. Both original symbols are destroyed. */
+
+SYMBOL *concat_symbols
+(     MPL *mpl,
+      SYMBOL *sym1,           /* destroyed */
+      SYMBOL *sym2            /* destroyed */
+)
+{     char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1];
+      xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG);
+      if (sym1->str == NULL)
+         sprintf(str1, "%.*g", DBL_DIG, sym1->num);
+      else
+         fetch_string(mpl, sym1->str, str1);
+      if (sym2->str == NULL)
+         sprintf(str2, "%.*g", DBL_DIG, sym2->num);
+      else
+         fetch_string(mpl, sym2->str, str2);
+      if (strlen(str1) + strlen(str2) > MAX_LENGTH)
+      {  char buf[255+1];
+         strcpy(buf, format_symbol(mpl, sym1));
+         xassert(strlen(buf) < sizeof(buf));
+         error(mpl, "%s & %s; resultant symbol exceeds %d characters",
+            buf, format_symbol(mpl, sym2), MAX_LENGTH);
+      }
+      delete_symbol(mpl, sym1);
+      delete_symbol(mpl, sym2);
+      return create_symbol_str(mpl, create_string(mpl, strcat(str1,
+         str2)));
+}
+
+/**********************************************************************/
+/* * *                          N-TUPLES                          * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_tuple - create n-tuple.
+--
+-- This routine creates a n-tuple, which initially has no components,
+-- i.e. which is 0-tuple. */
+
+TUPLE *create_tuple(MPL *mpl)
+{     TUPLE *tuple;
+      xassert(mpl == mpl);
+      tuple = NULL;
+      return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- expand_tuple - append symbol to n-tuple.
+--
+-- This routine expands n-tuple appending to it a given symbol, which
+-- becomes its new last component. */
+
+TUPLE *expand_tuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* destroyed */
+      SYMBOL *sym             /* destroyed */
+)
+{     TUPLE *tail, *temp;
+      xassert(sym != NULL);
+      /* create a new component */
+      tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+      tail->sym = sym;
+      tail->next = NULL;
+      /* and append it to the component list */
+      if (tuple == NULL)
+         tuple = tail;
+      else
+      {  for (temp = tuple; temp->next != NULL; temp = temp->next);
+         temp->next = tail;
+      }
+      return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- tuple_dimen - determine dimension of n-tuple.
+--
+-- This routine returns dimension of n-tuple, i.e. number of components
+-- in the n-tuple. */
+
+int tuple_dimen
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+)
+{     TUPLE *temp;
+      int dim = 0;
+      xassert(mpl == mpl);
+      for (temp = tuple; temp != NULL; temp = temp->next) dim++;
+      return dim;
+}
+
+/*----------------------------------------------------------------------
+-- copy_tuple - make copy of n-tuple.
+--
+-- This routine returns an exact copy of n-tuple. */
+
+TUPLE *copy_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* not changed */
+)
+{     TUPLE *head, *tail;
+      if (tuple == NULL)
+         head = NULL;
+      else
+      {  head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+         for (; tuple != NULL; tuple = tuple->next)
+         {  xassert(tuple->sym != NULL);
+            tail->sym = copy_symbol(mpl, tuple->sym);
+            if (tuple->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
+         }
+         tail->next = NULL;
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- compare_tuples - compare one n-tuple with another.
+--
+-- This routine compares two given n-tuples, which must have the same
+-- dimension (not checked for the sake of efficiency), and returns one
+-- of the following codes:
+--
+-- = 0 - both n-tuples are identical;
+-- < 0 - the first n-tuple precedes the second one;
+-- > 0 - the first n-tuple follows the second one.
+--
+-- Note that the linear order, in which n-tuples follow each other, is
+-- implementation-dependent. It may be not an alphabetical order. */
+
+int compare_tuples
+(     MPL *mpl,
+      TUPLE *tuple1,          /* not changed */
+      TUPLE *tuple2           /* not changed */
+)
+{     TUPLE *item1, *item2;
+      int ret;
+      xassert(mpl == mpl);
+      for (item1 = tuple1, item2 = tuple2; item1 != NULL;
+           item1 = item1->next, item2 = item2->next)
+      {  xassert(item2 != NULL);
+         xassert(item1->sym != NULL);
+         xassert(item2->sym != NULL);
+         ret = compare_symbols(mpl, item1->sym, item2->sym);
+         if (ret != 0) return ret;
+      }
+      xassert(item2 == NULL);
+      return 0;
+}
+
+/*----------------------------------------------------------------------
+-- build_subtuple - build subtuple of given n-tuple.
+--
+-- This routine builds subtuple, which consists of first dim components
+-- of given n-tuple. */
+
+TUPLE *build_subtuple
+(     MPL *mpl,
+      TUPLE *tuple,           /* not changed */
+      int dim
+)
+{     TUPLE *head, *temp;
+      int j;
+      head = create_tuple(mpl);
+      for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next)
+      {  xassert(temp != NULL);
+         head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym));
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- delete_tuple - delete n-tuple.
+--
+-- This routine deletes specified n-tuple. */
+
+void delete_tuple
+(     MPL *mpl,
+      TUPLE *tuple            /* destroyed */
+)
+{     TUPLE *temp;
+      while (tuple != NULL)
+      {  temp = tuple;
+         tuple = temp->next;
+         xassert(temp->sym != NULL);
+         delete_symbol(mpl, temp->sym);
+         dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- format_tuple - format n-tuple for displaying or printing.
+--
+-- This routine converts specified n-tuple to a character string, which
+-- is suitable for displaying or printing.
+--
+-- The resultant string is never longer than 255 characters. If it gets
+-- longer, it is truncated from the right and appended by dots. */
+
+char *format_tuple
+(     MPL *mpl,
+      int c,
+      TUPLE *tuple            /* not changed */
+)
+{     TUPLE *temp;
+      int dim, j, len;
+      char *buf = mpl->tup_buf, str[255+1], *save;
+#     define safe_append(c) \
+         (void)(len < 255 ? (buf[len++] = (char)(c)) : 0)
+      buf[0] = '\0', len = 0;
+      dim = tuple_dimen(mpl, tuple);
+      if (c == '[' && dim > 0) safe_append('[');
+      if (c == '(' && dim > 1) safe_append('(');
+      for (temp = tuple; temp != NULL; temp = temp->next)
+      {  if (temp != tuple) safe_append(',');
+         xassert(temp->sym != NULL);
+         save = mpl->sym_buf;
+         mpl->sym_buf = str;
+         format_symbol(mpl, temp->sym);
+         mpl->sym_buf = save;
+         xassert(strlen(str) < sizeof(str));
+         for (j = 0; str[j] != '\0'; j++) safe_append(str[j]);
+      }
+      if (c == '[' && dim > 0) safe_append(']');
+      if (c == '(' && dim > 1) safe_append(')');
+#     undef safe_append
+      buf[len] = '\0';
+      if (len == 255) strcpy(buf+252, "...");
+      xassert(strlen(buf) <= 255);
+      return buf;
+}
+
+/**********************************************************************/
+/* * *                       ELEMENTAL SETS                       * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_elemset - create elemental set.
+--
+-- This routine creates an elemental set, whose members are n-tuples of
+-- specified dimension. Being created the set is initially empty. */
+
+ELEMSET *create_elemset(MPL *mpl, int dim)
+{     ELEMSET *set;
+      xassert(dim > 0);
+      set = create_array(mpl, A_NONE, dim);
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- find_tuple - check if elemental set contains given n-tuple.
+--
+-- This routine finds given n-tuple in specified elemental set in order
+-- to check if the set contains that n-tuple. If the n-tuple is found,
+-- the routine returns pointer to corresponding array member. Otherwise
+-- null pointer is returned. */
+
+MEMBER *find_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      xassert(set->dim == tuple_dimen(mpl, tuple));
+      return find_member(mpl, set, tuple);
+}
+
+/*----------------------------------------------------------------------
+-- add_tuple - add new n-tuple to elemental set.
+--
+-- This routine adds given n-tuple to specified elemental set.
+--
+-- For the sake of efficiency this routine doesn't check whether the
+-- set already contains the same n-tuple or not. Therefore the calling
+-- program should use the routine find_tuple (if necessary) in order to
+-- make sure that the given n-tuple is not contained in the set, since
+-- duplicate n-tuples within the same set are not allowed. */
+
+MEMBER *add_tuple
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      xassert(set->dim == tuple_dimen(mpl, tuple));
+      memb = add_member(mpl, set, tuple);
+      memb->value.none = NULL;
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- check_then_add - check and add new n-tuple to elemental set.
+--
+-- This routine is equivalent to the routine add_tuple except that it
+-- does check for duplicate n-tuples. */
+
+MEMBER *check_then_add
+(     MPL *mpl,
+      ELEMSET *set,           /* modified */
+      TUPLE *tuple            /* destroyed */
+)
+{     if (find_tuple(mpl, set, tuple) != NULL)
+         error(mpl, "duplicate tuple %s detected", format_tuple(mpl,
+            '(', tuple));
+      return add_tuple(mpl, set, tuple);
+}
+
+/*----------------------------------------------------------------------
+-- copy_elemset - make copy of elemental set.
+--
+-- This routine makes an exact copy of elemental set. */
+
+ELEMSET *copy_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* not changed */
+)
+{     ELEMSET *copy;
+      MEMBER *memb;
+      xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      xassert(set->dim > 0);
+      copy = create_elemset(mpl, set->dim);
+      for (memb = set->head; memb != NULL; memb = memb->next)
+         add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple));
+      return copy;
+}
+
+/*----------------------------------------------------------------------
+-- delete_elemset - delete elemental set.
+--
+-- This routine deletes specified elemental set. */
+
+void delete_elemset
+(     MPL *mpl,
+      ELEMSET *set            /* destroyed */
+)
+{     xassert(set != NULL);
+      xassert(set->type == A_NONE);
+      delete_array(mpl, set);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- arelset_size - compute size of "arithmetic" elemental set.
+--
+-- This routine computes the size of "arithmetic" elemental set, which
+-- is specified in the form of arithmetic progression:
+--
+--    { t0 .. tf by dt }.
+--
+-- The size is computed using the formula:
+--
+--    n = max(0, floor((tf - t0) / dt) + 1). */
+
+int arelset_size(MPL *mpl, double t0, double tf, double dt)
+{     double temp;
+      if (dt == 0.0)
+         error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed",
+            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
+      if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0)
+         temp = +DBL_MAX;
+      else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0)
+         temp = -DBL_MAX;
+      else
+         temp = tf - t0;
+      if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt))
+      {  if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0)
+            temp = +DBL_MAX;
+         else
+            temp = 0.0;
+      }
+      else
+      {  temp = floor(temp / dt) + 1.0;
+         if (temp < 0.0) temp = 0.0;
+      }
+      xassert(temp >= 0.0);
+      if (temp > (double)(INT_MAX - 1))
+         error(mpl, "%.*g .. %.*g by %.*g; set too large",
+            DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt);
+      return (int)(temp + 0.5);
+}
+
+/*----------------------------------------------------------------------
+-- arelset_member - compute member of "arithmetic" elemental set.
+--
+-- This routine returns a numeric value of symbol, which is equivalent
+-- to j-th member of given "arithmetic" elemental set specified in the
+-- form of arithmetic progression:
+--
+--    { t0 .. tf by dt }.
+--
+-- The symbol value is computed with the formula:
+--
+--    j-th member = t0 + (j - 1) * dt,
+--
+-- The number j must satisfy to the restriction 1 <= j <= n, where n is
+-- the set size computed by the routine arelset_size. */
+
+double arelset_member(MPL *mpl, double t0, double tf, double dt, int j)
+{     xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt));
+      return t0 + (double)(j - 1) * dt;
+}
+
+/*----------------------------------------------------------------------
+-- create_arelset - create "arithmetic" elemental set.
+--
+-- This routine creates "arithmetic" elemental set, which is specified
+-- in the form of arithmetic progression:
+--
+--    { t0 .. tf by dt }.
+--
+-- Components of this set are 1-tuples. */
+
+ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt)
+{     ELEMSET *set;
+      int j, n;
+      set = create_elemset(mpl, 1);
+      n = arelset_size(mpl, t0, tf, dt);
+      for (j = 1; j <= n; j++)
+      {  add_tuple
+         (  mpl,
+            set,
+            expand_tuple
+            (  mpl,
+               create_tuple(mpl),
+               create_symbol_num
+               (  mpl,
+                  arelset_member(mpl, t0, tf, dt, j)
+               )
+            )
+         );
+      }
+      return set;
+}
+
+/*----------------------------------------------------------------------
+-- set_union - union of two elemental sets.
+--
+-- This routine computes the union:
+--
+--    X U Y = { j | (j in X) or (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_union
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      for (memb = Y->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
+            add_tuple(mpl, X, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, Y);
+      return X;
+}
+
+/*----------------------------------------------------------------------
+-- set_diff - difference between two elemental sets.
+--
+-- This routine computes the difference:
+--
+--    X \ Y = { j | (j in X) and (j not in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_diff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      Z = create_elemset(mpl, X->dim);
+      for (memb = X->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_symdiff - symmetric difference between two elemental sets.
+--
+-- This routine computes the symmetric difference:
+--
+--    X (+) Y = (X \ Y) U (Y \ X),
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_symdiff
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      /* Z := X \ Y */
+      Z = create_elemset(mpl, X->dim);
+      for (memb = X->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, Y, memb->tuple) == NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      /* Z := Z U (Y \ X) */
+      for (memb = Y->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, X, memb->tuple) == NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_inter - intersection of two elemental sets.
+--
+-- This routine computes the intersection:
+--
+--    X ^ Y = { j | (j in X) and (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_inter
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memb;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      xassert(X->dim == Y->dim);
+      Z = create_elemset(mpl, X->dim);
+      for (memb = X->head; memb != NULL; memb = memb->next)
+      {  if (find_tuple(mpl, Y, memb->tuple) != NULL)
+            add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple));
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/*----------------------------------------------------------------------
+-- set_cross - cross (Cartesian) product of two elemental sets.
+--
+-- This routine computes the cross (Cartesian) product:
+--
+--    X x Y = { (i,j) | (i in X) and (j in Y) },
+--
+-- where X and Y are given elemental sets (destroyed on exit). */
+
+ELEMSET *set_cross
+(     MPL *mpl,
+      ELEMSET *X,             /* destroyed */
+      ELEMSET *Y              /* destroyed */
+)
+{     ELEMSET *Z;
+      MEMBER *memx, *memy;
+      TUPLE *tuple, *temp;
+      xassert(X != NULL);
+      xassert(X->type == A_NONE);
+      xassert(X->dim > 0);
+      xassert(Y != NULL);
+      xassert(Y->type == A_NONE);
+      xassert(Y->dim > 0);
+      Z = create_elemset(mpl, X->dim + Y->dim);
+      for (memx = X->head; memx != NULL; memx = memx->next)
+      {  for (memy = Y->head; memy != NULL; memy = memy->next)
+         {  tuple = copy_tuple(mpl, memx->tuple);
+            for (temp = memy->tuple; temp != NULL; temp = temp->next)
+               tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                  temp->sym));
+            add_tuple(mpl, Z, tuple);
+         }
+      }
+      delete_elemset(mpl, X);
+      delete_elemset(mpl, Y);
+      return Z;
+}
+
+/**********************************************************************/
+/* * *                    ELEMENTAL VARIABLES                     * * */
+/**********************************************************************/
+
+/* (there are no specific routines for elemental variables) */
+
+/**********************************************************************/
+/* * *                        LINEAR FORMS                        * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- constant_term - create constant term.
+--
+-- This routine creates the linear form, which is a constant term. */
+
+FORMULA *constant_term(MPL *mpl, double coef)
+{     FORMULA *form;
+      if (coef == 0.0)
+         form = NULL;
+      else
+      {  form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+         form->coef = coef;
+         form->var = NULL;
+         form->next = NULL;
+      }
+      return form;
+}
+
+/*----------------------------------------------------------------------
+-- single_variable - create single variable.
+--
+-- This routine creates the linear form, which is a single elemental
+-- variable. */
+
+FORMULA *single_variable
+(     MPL *mpl,
+      ELEMVAR *var            /* referenced */
+)
+{     FORMULA *form;
+      xassert(var != NULL);
+      form = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+      form->coef = 1.0;
+      form->var = var;
+      form->next = NULL;
+      return form;
+}
+
+/*----------------------------------------------------------------------
+-- copy_formula - make copy of linear form.
+--
+-- This routine returns an exact copy of linear form. */
+
+FORMULA *copy_formula
+(     MPL *mpl,
+      FORMULA *form           /* not changed */
+)
+{     FORMULA *head, *tail;
+      if (form == NULL)
+         head = NULL;
+      else
+      {  head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+         for (; form != NULL; form = form->next)
+         {  tail->coef = form->coef;
+            tail->var = form->var;
+            if (form->next != NULL)
+tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA)));
+         }
+         tail->next = NULL;
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- delete_formula - delete linear form.
+--
+-- This routine deletes specified linear form. */
+
+void delete_formula
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+)
+{     FORMULA *temp;
+      while (form != NULL)
+      {  temp = form;
+         form = form->next;
+         dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- linear_comb - linear combination of two linear forms.
+--
+-- This routine computes the linear combination:
+--
+--    a * fx + b * fy,
+--
+-- where a and b are numeric coefficients, fx and fy are linear forms
+-- (destroyed on exit). */
+
+FORMULA *linear_comb
+(     MPL *mpl,
+      double a, FORMULA *fx,  /* destroyed */
+      double b, FORMULA *fy   /* destroyed */
+)
+{     FORMULA *form = NULL, *term, *temp;
+      double c0 = 0.0;
+      for (term = fx; term != NULL; term = term->next)
+      {  if (term->var == NULL)
+            c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef));
+         else
+            term->var->temp =
+               fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef));
+      }
+      for (term = fy; term != NULL; term = term->next)
+      {  if (term->var == NULL)
+            c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef));
+         else
+            term->var->temp =
+               fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef));
+      }
+      for (term = fx; term != NULL; term = term->next)
+      {  if (term->var != NULL && term->var->temp != 0.0)
+         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+            temp->coef = term->var->temp, temp->var = term->var;
+            temp->next = form, form = temp;
+            term->var->temp = 0.0;
+         }
+      }
+      for (term = fy; term != NULL; term = term->next)
+      {  if (term->var != NULL && term->var->temp != 0.0)
+         {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+            temp->coef = term->var->temp, temp->var = term->var;
+            temp->next = form, form = temp;
+            term->var->temp = 0.0;
+         }
+      }
+      if (c0 != 0.0)
+      {  temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA));
+         temp->coef = c0, temp->var = NULL;
+         temp->next = form, form = temp;
+      }
+      delete_formula(mpl, fx);
+      delete_formula(mpl, fy);
+      return form;
+}
+
+/*----------------------------------------------------------------------
+-- remove_constant - remove constant term from linear form.
+--
+-- This routine removes constant term from linear form and stores its
+-- value to given location. */
+
+FORMULA *remove_constant
+(     MPL *mpl,
+      FORMULA *form,          /* destroyed */
+      double *coef            /* modified */
+)
+{     FORMULA *head = NULL, *temp;
+      *coef = 0.0;
+      while (form != NULL)
+      {  temp = form;
+         form = form->next;
+         if (temp->var == NULL)
+         {  /* constant term */
+            *coef = fp_add(mpl, *coef, temp->coef);
+            dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA));
+         }
+         else
+         {  /* linear term */
+            temp->next = head;
+            head = temp;
+         }
+      }
+      return head;
+}
+
+/*----------------------------------------------------------------------
+-- reduce_terms - reduce identical terms in linear form.
+--
+-- This routine reduces identical terms in specified linear form. */
+
+FORMULA *reduce_terms
+(     MPL *mpl,
+      FORMULA *form           /* destroyed */
+)
+{     FORMULA *term, *next_term;
+      double c0 = 0.0;
+      for (term = form; term != NULL; term = term->next)
+      {  if (term->var == NULL)
+            c0 = fp_add(mpl, c0, term->coef);
+         else
+            term->var->temp = fp_add(mpl, term->var->temp, term->coef);
+      }
+      next_term = form, form = NULL;
+      for (term = next_term; term != NULL; term = next_term)
+      {  next_term = term->next;
+         if (term->var == NULL && c0 != 0.0)
+         {  term->coef = c0, c0 = 0.0;
+            term->next = form, form = term;
+         }
+         else if (term->var != NULL && term->var->temp != 0.0)
+         {  term->coef = term->var->temp, term->var->temp = 0.0;
+            term->next = form, form = term;
+         }
+         else
+            dmp_free_atom(mpl->formulae, term, sizeof(FORMULA));
+      }
+      return form;
+}
+
+/**********************************************************************/
+/* * *                   ELEMENTAL CONSTRAINTS                    * * */
+/**********************************************************************/
+
+/* (there are no specific routines for elemental constraints) */
+
+/**********************************************************************/
+/* * *                       GENERIC VALUES                       * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- delete_value - delete generic value.
+--
+-- This routine deletes specified generic value.
+--
+-- NOTE: The generic value to be deleted must be valid. */
+
+void delete_value
+(     MPL *mpl,
+      int type,
+      VALUE *value            /* content destroyed */
+)
+{     xassert(value != NULL);
+      switch (type)
+      {  case A_NONE:
+            value->none = NULL;
+            break;
+         case A_NUMERIC:
+            value->num = 0.0;
+            break;
+         case A_SYMBOLIC:
+            delete_symbol(mpl, value->sym), value->sym = NULL;
+            break;
+         case A_LOGICAL:
+            value->bit = 0;
+            break;
+         case A_TUPLE:
+            delete_tuple(mpl, value->tuple), value->tuple = NULL;
+            break;
+         case A_ELEMSET:
+            delete_elemset(mpl, value->set), value->set = NULL;
+            break;
+         case A_ELEMVAR:
+            value->var = NULL;
+            break;
+         case A_FORMULA:
+            delete_formula(mpl, value->form), value->form = NULL;
+            break;
+         case A_ELEMCON:
+            value->con = NULL;
+            break;
+         default:
+            xassert(type != type);
+      }
+      return;
+}
+
+/**********************************************************************/
+/* * *                SYMBOLICALLY INDEXED ARRAYS                 * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- create_array - create array.
+--
+-- This routine creates an array of specified type and dimension. Being
+-- created the array is initially empty.
+--
+-- The type indicator determines generic values, which can be assigned
+-- to the array members:
+--
+-- A_NONE     - none (members have no assigned values)
+-- A_NUMERIC  - floating-point numbers
+-- A_SYMBOLIC - symbols
+-- A_ELEMSET  - elemental sets
+-- A_ELEMVAR  - elemental variables
+-- A_ELEMCON  - elemental constraints
+--
+-- The dimension may be 0, in which case the array consists of the only
+-- member (such arrays represent 0-dimensional objects). */
+
+ARRAY *create_array(MPL *mpl, int type, int dim)
+{     ARRAY *array;
+      xassert(type == A_NONE || type == A_NUMERIC ||
+             type == A_SYMBOLIC || type == A_ELEMSET ||
+             type == A_ELEMVAR || type == A_ELEMCON);
+      xassert(dim >= 0);
+      array = dmp_get_atom(mpl->arrays, sizeof(ARRAY));
+      array->type = type;
+      array->dim = dim;
+      array->size = 0;
+      array->head = NULL;
+      array->tail = NULL;
+      array->tree = NULL;
+      array->prev = NULL;
+      array->next = mpl->a_list;
+      /* include the array in the global array list */
+      if (array->next != NULL) array->next->prev = array;
+      mpl->a_list = array;
+      return array;
+}
+
+/*----------------------------------------------------------------------
+-- find_member - find array member with given n-tuple.
+--
+-- This routine finds an array member, which has given n-tuple. If the
+-- array is short, the linear search is used. Otherwise the routine
+-- autimatically creates the search tree (i.e. the array index) to find
+-- members for logarithmic time. */
+
+static int compare_member_tuples(void *info, const void *key1,
+      const void *key2)
+{     /* this is an auxiliary routine used to compare keys, which are
+         n-tuples assigned to array members */
+      return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2);
+}
+
+MEMBER *find_member
+(     MPL *mpl,
+      ARRAY *array,           /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      xassert(array != NULL);
+      /* the n-tuple must have the same dimension as the array */
+      xassert(tuple_dimen(mpl, tuple) == array->dim);
+      /* if the array is large enough, create the search tree and index
+         all existing members of the array */
+      if (array->size > 30 && array->tree == NULL)
+      {  array->tree = avl_create_tree(compare_member_tuples, mpl);
+         for (memb = array->head; memb != NULL; memb = memb->next)
+avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
+               (void *)memb);
+      }
+      /* find a member, which has the given tuple */
+      if (array->tree == NULL)
+      {  /* the search tree doesn't exist; use the linear search */
+         for (memb = array->head; memb != NULL; memb = memb->next)
+            if (compare_tuples(mpl, memb->tuple, tuple) == 0) break;
+      }
+      else
+      {  /* the search tree exists; use the binary search */
+         AVLNODE *node;
+         node = avl_find_node(array->tree, tuple);
+memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node));
+      }
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- add_member - add new member to array.
+--
+-- This routine creates a new member with given n-tuple and adds it to
+-- specified array.
+--
+-- For the sake of efficiency this routine doesn't check whether the
+-- array already contains a member with the given n-tuple or not. Thus,
+-- if necessary, the calling program should use the routine find_member
+-- in order to be sure that the array contains no member with the same
+-- n-tuple, because members with duplicate n-tuples are not allowed.
+--
+-- This routine assigns no generic value to the new member, because the
+-- calling program must do that. */
+
+MEMBER *add_member
+(     MPL *mpl,
+      ARRAY *array,           /* modified */
+      TUPLE *tuple            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(array != NULL);
+      /* the n-tuple must have the same dimension as the array */
+      xassert(tuple_dimen(mpl, tuple) == array->dim);
+      /* create new member */
+      memb = dmp_get_atom(mpl->members, sizeof(MEMBER));
+      memb->tuple = tuple;
+      memb->next = NULL;
+      memset(&memb->value, '?', sizeof(VALUE));
+      /* and append it to the member list */
+      array->size++;
+      if (array->head == NULL)
+         array->head = memb;
+      else
+         array->tail->next = memb;
+      array->tail = memb;
+      /* if the search tree exists, index the new member */
+      if (array->tree != NULL)
+avl_set_node_link(avl_insert_node(array->tree, memb->tuple),
+            (void *)memb);
+      return memb;
+}
+
+/*----------------------------------------------------------------------
+-- delete_array - delete array.
+--
+-- This routine deletes specified array.
+--
+-- Generic values assigned to the array members are not deleted by this
+-- routine. The calling program itself must delete all assigned generic
+-- values before deleting the array. */
+
+void delete_array
+(     MPL *mpl,
+      ARRAY *array            /* destroyed */
+)
+{     MEMBER *memb;
+      xassert(array != NULL);
+      /* delete all existing array members */
+      while (array->head != NULL)
+      {  memb = array->head;
+         array->head = memb->next;
+         delete_tuple(mpl, memb->tuple);
+         dmp_free_atom(mpl->members, memb, sizeof(MEMBER));
+      }
+      /* if the search tree exists, also delete it */
+      if (array->tree != NULL) avl_delete_tree(array->tree);
+      /* remove the array from the global array list */
+      if (array->prev == NULL)
+         mpl->a_list = array->next;
+      else
+         array->prev->next = array->next;
+      if (array->next == NULL)
+         ;
+      else
+         array->next->prev = array->prev;
+      /* delete the array descriptor */
+      dmp_free_atom(mpl->arrays, array, sizeof(ARRAY));
+      return;
+}
+
+/**********************************************************************/
+/* * *                 DOMAINS AND DUMMY INDICES                  * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- assign_dummy_index - assign new value to dummy index.
+--
+-- This routine assigns new value to specified dummy index and, that is
+-- important, invalidates all temporary resultant values, which depends
+-- on that dummy index. */
+
+void assign_dummy_index
+(     MPL *mpl,
+      DOMAIN_SLOT *slot,      /* modified */
+      SYMBOL *value           /* not changed */
+)
+{     CODE *leaf, *code;
+      xassert(slot != NULL);
+      xassert(value != NULL);
+      /* delete the current value assigned to the dummy index */
+      if (slot->value != NULL)
+      {  /* if the current value and the new one are identical, actual
+            assignment is not needed */
+         if (compare_symbols(mpl, slot->value, value) == 0) goto done;
+         /* delete a symbol, which is the current value */
+         delete_symbol(mpl, slot->value), slot->value = NULL;
+      }
+      /* now walk through all the pseudo-codes with op = O_INDEX, which
+         refer to the dummy index to be changed (these pseudo-codes are
+         leaves in the forest of *all* expressions in the database) */
+      for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index.
+         next)
+      {  xassert(leaf->op == O_INDEX);
+         /* invalidate all resultant values, which depend on the dummy
+            index, walking from the current leaf toward the root of the
+            corresponding expression tree */
+         for (code = leaf; code != NULL; code = code->up)
+         {  if (code->valid)
+            {  /* invalidate and delete resultant value */
+               code->valid = 0;
+               delete_value(mpl, code->type, &code->value);
+            }
+         }
+      }
+      /* assign new value to the dummy index */
+      slot->value = copy_symbol(mpl, value);
+done: return;
+}
+
+/*----------------------------------------------------------------------
+-- update_dummy_indices - update current values of dummy indices.
+--
+-- This routine assigns components of "backup" n-tuple to dummy indices
+-- of specified domain block. If no "backup" n-tuple is defined for the
+-- domain block, values of the dummy indices remain untouched. */
+
+void update_dummy_indices
+(     MPL *mpl,
+      DOMAIN_BLOCK *block     /* not changed */
+)
+{     DOMAIN_SLOT *slot;
+      TUPLE *temp;
+      if (block->backup != NULL)
+      {  for (slot = block->list, temp = block->backup; slot != NULL;
+            slot = slot->next, temp = temp->next)
+         {  xassert(temp != NULL);
+            xassert(temp->sym != NULL);
+            assign_dummy_index(mpl, slot, temp->sym);
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- enter_domain_block - enter domain block.
+--
+-- Let specified domain block have the form:
+--
+--    { ..., (j1, j2, ..., jn) in J, ... }
+--
+-- where j1, j2, ..., jn are dummy indices, J is a basic set.
+--
+-- This routine does the following:
+--
+-- 1. Checks if the given n-tuple is a member of the basic set J. Note
+--    that J being *out of the scope* of the domain block cannot depend
+--    on the dummy indices in the same and inner domain blocks, so it
+--    can be computed before the dummy indices are assigned new values.
+--    If this check fails, the routine returns with non-zero code.
+--
+-- 2. Saves current values of the dummy indices j1, j2, ..., jn.
+--
+-- 3. Assigns new values, which are components of the given n-tuple, to
+--    the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is
+--    larger than n, its extra components n+1, n+2, ... are not used.
+--
+-- 4. Calls the formal routine func which either enters the next domain
+--    block or evaluates some code within the domain scope.
+--
+-- 5. Restores former values of the dummy indices j1, j2, ..., jn.
+--
+-- Since current values assigned to the dummy indices on entry to this
+-- routine are restored on exit, the formal routine func is allowed to
+-- call this routine recursively. */
+
+int enter_domain_block
+(     MPL *mpl,
+      DOMAIN_BLOCK *block,    /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+)
+{     TUPLE *backup;
+      int ret = 0;
+      /* check if the given n-tuple is a member of the basic set */
+      xassert(block->code != NULL);
+      if (!is_member(mpl, block->code, tuple))
+      {  ret = 1;
+         goto done;
+      }
+      /* save reference to "backup" n-tuple, which was used to assign
+         current values of the dummy indices (it is sufficient to save
+         reference, not value, because that n-tuple is defined in some
+         outer level of recursion and therefore cannot be changed on
+         this and deeper recursive calls) */
+      backup = block->backup;
+      /* set up new "backup" n-tuple, which defines new values of the
+         dummy indices */
+      block->backup = tuple;
+      /* assign new values to the dummy indices */
+      update_dummy_indices(mpl, block);
+      /* call the formal routine that does the rest part of the job */
+      func(mpl, info);
+      /* restore reference to the former "backup" n-tuple */
+      block->backup = backup;
+      /* restore former values of the dummy indices; note that if the
+         domain block just escaped has no other active instances which
+         may exist due to recursion (it is indicated by a null pointer
+         to the former n-tuple), former values of the dummy indices are
+         undefined; therefore in this case the routine keeps currently
+         assigned values of the dummy indices that involves keeping all
+         dependent temporary results and thereby, if this domain block
+         is not used recursively, allows improving efficiency */
+      update_dummy_indices(mpl, block);
+done: return ret;
+}
+
+/*----------------------------------------------------------------------
+-- eval_within_domain - perform evaluation within domain scope.
+--
+-- This routine assigns new values (symbols) to all dummy indices of
+-- specified domain and calls the formal routine func, which is used to
+-- evaluate some code in the domain scope. Each free dummy index in the
+-- domain is assigned a value specified in the corresponding component
+-- of given n-tuple. Non-free dummy indices are assigned values, which
+-- are computed by this routine.
+--
+-- Number of components in the given n-tuple must be the same as number
+-- of free indices in the domain.
+--
+-- If the given n-tuple is not a member of the domain set, the routine
+-- func is not called, and non-zero code is returned.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL
+-- (then n-tuple also must be 0-tuple, i.e. empty), in which case this
+-- routine just calls the routine func and returns zero.
+--
+-- This routine allows recursive calls from the routine func providing
+-- correct values of dummy indices for each instance.
+--
+-- NOTE: The n-tuple passed to this routine must not be changed by any
+--       other routines called from the formal routine func until this
+--       routine has returned. */
+
+struct eval_domain_info
+{     /* working info used by the routine eval_within_domain */
+      DOMAIN *domain;
+      /* domain, which has to be entered */
+      DOMAIN_BLOCK *block;
+      /* domain block, which is currently processed */
+      TUPLE *tuple;
+      /* tail of original n-tuple, whose components have to be assigned
+         to free dummy indices in the current domain block */
+      void *info;
+      /* transit pointer passed to the formal routine func */
+      void (*func)(MPL *mpl, void *info);
+      /* routine, which has to be executed in the domain scope */
+      int failure;
+      /* this flag indicates that given n-tuple is not a member of the
+         domain set */
+};
+
+static void eval_domain_func(MPL *mpl, void *_my_info)
+{     /* this routine recursively enters into the domain scope and then
+         calls the routine func */
+      struct eval_domain_info *my_info = _my_info;
+      if (my_info->block != NULL)
+      {  /* the current domain block to be entered exists */
+         DOMAIN_BLOCK *block;
+         DOMAIN_SLOT *slot;
+         TUPLE *tuple = NULL, *temp = NULL;
+         /* save pointer to the current domain block */
+         block = my_info->block;
+         /* and get ready to enter the next block (if it exists) */
+         my_info->block = block->next;
+         /* construct temporary n-tuple, whose components correspond to
+            dummy indices (slots) of the current domain; components of
+            the temporary n-tuple that correspond to free dummy indices
+            are assigned references (not values!) to symbols specified
+            in the corresponding components of the given n-tuple, while
+            other components that correspond to non-free dummy indices
+            are assigned symbolic values computed here */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  /* create component that corresponds to the current slot */
+            if (tuple == NULL)
+               tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE));
+            else
+temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE)));
+            if (slot->code == NULL)
+            {  /* dummy index is free; take reference to symbol, which
+                  is specified in the corresponding component of given
+                  n-tuple */
+               xassert(my_info->tuple != NULL);
+               temp->sym = my_info->tuple->sym;
+               xassert(temp->sym != NULL);
+               my_info->tuple = my_info->tuple->next;
+            }
+            else
+            {  /* dummy index is non-free; compute symbolic value to be
+                  temporarily assigned to the dummy index */
+               temp->sym = eval_symbolic(mpl, slot->code);
+            }
+         }
+         temp->next = NULL;
+         /* enter the current domain block */
+         if (enter_domain_block(mpl, block, tuple, my_info,
+               eval_domain_func)) my_info->failure = 1;
+         /* delete temporary n-tuple as well as symbols that correspond
+            to non-free dummy indices (they were computed here) */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  xassert(tuple != NULL);
+            temp = tuple;
+            tuple = tuple->next;
+            if (slot->code != NULL)
+            {  /* dummy index is non-free; delete symbolic value */
+               delete_symbol(mpl, temp->sym);
+            }
+            /* delete component that corresponds to the current slot */
+            dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE));
+         }
+      }
+      else
+      {  /* there are no more domain blocks, i.e. we have reached the
+            domain scope */
+         xassert(my_info->tuple == NULL);
+         /* check optional predicate specified for the domain */
+         if (my_info->domain->code != NULL && !eval_logical(mpl,
+            my_info->domain->code))
+         {  /* the predicate is false */
+            my_info->failure = 2;
+         }
+         else
+         {  /* the predicate is true; do the job */
+            my_info->func(mpl, my_info->info);
+         }
+      }
+      return;
+}
+
+int eval_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      void *info, void (*func)(MPL *mpl, void *info)
+)
+{     /* this routine performs evaluation within domain scope */
+      struct eval_domain_info _my_info, *my_info = &_my_info;
+      if (domain == NULL)
+      {  xassert(tuple == NULL);
+         func(mpl, info);
+         my_info->failure = 0;
+      }
+      else
+      {  xassert(tuple != NULL);
+         my_info->domain = domain;
+         my_info->block = domain->list;
+         my_info->tuple = tuple;
+         my_info->info = info;
+         my_info->func = func;
+         my_info->failure = 0;
+         /* enter the very first domain block */
+         eval_domain_func(mpl, my_info);
+      }
+      return my_info->failure;
+}
+
+/*----------------------------------------------------------------------
+-- loop_within_domain - perform iterations within domain scope.
+--
+-- This routine iteratively assigns new values (symbols) to the dummy
+-- indices of specified domain by enumerating all n-tuples, which are
+-- members of the domain set, and for every n-tuple it calls the formal
+-- routine func to evaluate some code within the domain scope.
+--
+-- If the routine func returns non-zero, enumeration within the domain
+-- is prematurely terminated.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL,
+-- in which case this routine just calls the routine func only once and
+-- returns zero.
+--
+-- This routine allows recursive calls from the routine func providing
+-- correct values of dummy indices for each instance. */
+
+struct loop_domain_info
+{     /* working info used by the routine loop_within_domain */
+      DOMAIN *domain;
+      /* domain, which has to be entered */
+      DOMAIN_BLOCK *block;
+      /* domain block, which is currently processed */
+      int looping;
+      /* clearing this flag leads to terminating enumeration */
+      void *info;
+      /* transit pointer passed to the formal routine func */
+      int (*func)(MPL *mpl, void *info);
+      /* routine, which needs to be executed in the domain scope */
+};
+
+static void loop_domain_func(MPL *mpl, void *_my_info)
+{     /* this routine enumerates all n-tuples in the basic set of the
+         current domain block, enters recursively into the domain scope
+         for every n-tuple, and then calls the routine func */
+      struct loop_domain_info *my_info = _my_info;
+      if (my_info->block != NULL)
+      {  /* the current domain block to be entered exists */
+         DOMAIN_BLOCK *block;
+         DOMAIN_SLOT *slot;
+         TUPLE *bound;
+         /* save pointer to the current domain block */
+         block = my_info->block;
+         /* and get ready to enter the next block (if it exists) */
+         my_info->block = block->next;
+         /* compute symbolic values, at which non-free dummy indices of
+            the current domain block are bound; since that values don't
+            depend on free dummy indices of the current block, they can
+            be computed once out of the enumeration loop */
+         bound = create_tuple(mpl);
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  if (slot->code != NULL)
+               bound = expand_tuple(mpl, bound, eval_symbolic(mpl,
+                  slot->code));
+         }
+         /* start enumeration */
+         xassert(block->code != NULL);
+         if (block->code->op == O_DOTS)
+         {  /* the basic set is "arithmetic", in which case it doesn't
+               need to be computed explicitly */
+            TUPLE *tuple;
+            int n, j;
+            double t0, tf, dt;
+            /* compute "parameters" of the basic set */
+            t0 = eval_numeric(mpl, block->code->arg.arg.x);
+            tf = eval_numeric(mpl, block->code->arg.arg.y);
+            if (block->code->arg.arg.z == NULL)
+               dt = 1.0;
+            else
+               dt = eval_numeric(mpl, block->code->arg.arg.z);
+            /* determine cardinality of the basic set */
+            n = arelset_size(mpl, t0, tf, dt);
+            /* create dummy 1-tuple for members of the basic set */
+            tuple = expand_tuple(mpl, create_tuple(mpl),
+               create_symbol_num(mpl, 0.0));
+            /* in case of "arithmetic" set there is exactly one dummy
+               index, which cannot be non-free */
+            xassert(bound == NULL);
+            /* walk through 1-tuples of the basic set */
+            for (j = 1; j <= n && my_info->looping; j++)
+            {  /* construct dummy 1-tuple for the current member */
+               tuple->sym->num = arelset_member(mpl, t0, tf, dt, j);
+               /* enter the current domain block */
+               enter_domain_block(mpl, block, tuple, my_info,
+                  loop_domain_func);
+            }
+            /* delete dummy 1-tuple */
+            delete_tuple(mpl, tuple);
+         }
+         else
+         {  /* the basic set is of general kind, in which case it needs
+               to be explicitly computed */
+            ELEMSET *set;
+            MEMBER *memb;
+            TUPLE *temp1, *temp2;
+            /* compute the basic set */
+            set = eval_elemset(mpl, block->code);
+            /* walk through all n-tuples of the basic set */
+            for (memb = set->head; memb != NULL && my_info->looping;
+               memb = memb->next)
+            {  /* all components of the current n-tuple that correspond
+                  to non-free dummy indices must be feasible; otherwise
+                  the n-tuple is not in the basic set */
+               temp1 = memb->tuple;
+               temp2 = bound;
+               for (slot = block->list; slot != NULL; slot = slot->next)
+               {  xassert(temp1 != NULL);
+                  if (slot->code != NULL)
+                  {  /* non-free dummy index */
+                     xassert(temp2 != NULL);
+                     if (compare_symbols(mpl, temp1->sym, temp2->sym)
+                        != 0)
+                     {  /* the n-tuple is not in the basic set */
+                        goto skip;
+                     }
+                     temp2 = temp2->next;
+                  }
+                  temp1 = temp1->next;
+               }
+               xassert(temp1 == NULL);
+               xassert(temp2 == NULL);
+               /* enter the current domain block */
+               enter_domain_block(mpl, block, memb->tuple, my_info,
+                  loop_domain_func);
+skip:          ;
+            }
+            /* delete the basic set */
+            delete_elemset(mpl, set);
+         }
+         /* delete symbolic values binding non-free dummy indices */
+         delete_tuple(mpl, bound);
+         /* restore pointer to the current domain block */
+         my_info->block = block;
+      }
+      else
+      {  /* there are no more domain blocks, i.e. we have reached the
+            domain scope */
+         /* check optional predicate specified for the domain */
+         if (my_info->domain->code != NULL && !eval_logical(mpl,
+            my_info->domain->code))
+         {  /* the predicate is false */
+            /* nop */;
+         }
+         else
+         {  /* the predicate is true; do the job */
+            my_info->looping = !my_info->func(mpl, my_info->info);
+         }
+      }
+      return;
+}
+
+void loop_within_domain
+(     MPL *mpl,
+      DOMAIN *domain,         /* not changed */
+      void *info, int (*func)(MPL *mpl, void *info)
+)
+{     /* this routine performs iterations within domain scope */
+      struct loop_domain_info _my_info, *my_info = &_my_info;
+      if (domain == NULL)
+         func(mpl, info);
+      else
+      {  my_info->domain = domain;
+         my_info->block = domain->list;
+         my_info->looping = 1;
+         my_info->info = info;
+         my_info->func = func;
+         /* enter the very first domain block */
+         loop_domain_func(mpl, my_info);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- out_of_domain - raise domain exception.
+--
+-- This routine is called when a reference is made to a member of some
+-- model object, but its n-tuple is out of the object domain. */
+
+void out_of_domain
+(     MPL *mpl,
+      char *name,             /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     xassert(name != NULL);
+      xassert(tuple != NULL);
+      error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[',
+         tuple));
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- get_domain_tuple - obtain current n-tuple from domain.
+--
+-- This routine constructs n-tuple, whose components are current values
+-- assigned to *free* dummy indices of specified domain.
+--
+-- For the sake of convenience it is allowed to specify domain as NULL,
+-- in which case this routine returns 0-tuple.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+TUPLE *get_domain_tuple
+(     MPL *mpl,
+      DOMAIN *domain          /* not changed */
+)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      TUPLE *tuple;
+      tuple = create_tuple(mpl);
+      if (domain != NULL)
+      {  for (block = domain->list; block != NULL; block = block->next)
+         {  for (slot = block->list; slot != NULL; slot = slot->next)
+            {  if (slot->code == NULL)
+               {  xassert(slot->value != NULL);
+                  tuple = expand_tuple(mpl, tuple, copy_symbol(mpl,
+                     slot->value));
+               }
+            }
+         }
+      }
+      return tuple;
+}
+
+/*----------------------------------------------------------------------
+-- clean_domain - clean domain.
+--
+-- This routine cleans specified domain that assumes deleting all stuff
+-- dynamically allocated during the generation phase. */
+
+void clean_domain(MPL *mpl, DOMAIN *domain)
+{     DOMAIN_BLOCK *block;
+      DOMAIN_SLOT *slot;
+      /* if no domain is specified, do nothing */
+      if (domain == NULL) goto done;
+      /* clean all domain blocks */
+      for (block = domain->list; block != NULL; block = block->next)
+      {  /* clean all domain slots */
+         for (slot = block->list; slot != NULL; slot = slot->next)
+         {  /* clean pseudo-code for computing bound value */
+            clean_code(mpl, slot->code);
+            /* delete symbolic value assigned to dummy index */
+            if (slot->value != NULL)
+               delete_symbol(mpl, slot->value), slot->value = NULL;
+         }
+         /* clean pseudo-code for computing basic set */
+         clean_code(mpl, block->code);
+      }
+      /* clean pseudo-code for computing domain predicate */
+      clean_code(mpl, domain->code);
+done: return;
+}
+
+/**********************************************************************/
+/* * *                         MODEL SETS                         * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- check_elem_set - check elemental set assigned to set member.
+--
+-- This routine checks if given elemental set being assigned to member
+-- of specified model set satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_elem_set
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple,           /* not changed */
+      ELEMSET *refer          /* not changed */
+)
+{     WITHIN *within;
+      MEMBER *memb;
+      int eqno;
+      /* elemental set must be within all specified supersets */
+      for (within = set->within, eqno = 1; within != NULL; within =
+         within->next, eqno++)
+      {  xassert(within->code != NULL);
+         for (memb = refer->head; memb != NULL; memb = memb->next)
+         {  if (!is_member(mpl, within->code, memb->tuple))
+            {  char buf[255+1];
+               strcpy(buf, format_tuple(mpl, '(', memb->tuple));
+               xassert(strlen(buf) < sizeof(buf));
+               error(mpl, "%s%s contains %s which not within specified "
+                  "set; see (%d)", set->name, format_tuple(mpl, '[',
+                     tuple), buf, eqno);
+            }
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_set - obtain elemental set assigned to set member.
+--
+-- This routine obtains a reference to elemental set assigned to given
+-- member of specified model set and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMSET *take_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      ELEMSET *refer;
+      /* find member in the set array */
+      memb = find_member(mpl, set->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take the reference */
+         refer = memb->value.set;
+      }
+      else if (set->assign != NULL)
+      {  /* compute value using assignment expression */
+         refer = eval_elemset(mpl, set->assign);
+add:     /* check that the elemental set satisfies to all restrictions,
+            assign it to new member, and add the member to the array */
+         check_elem_set(mpl, set, tuple, refer);
+         memb = add_member(mpl, set->array, copy_tuple(mpl, tuple));
+         memb->value.set = refer;
+      }
+      else if (set->option != NULL)
+      {  /* compute default elemental set */
+         refer = eval_elemset(mpl, set->option);
+         goto add;
+      }
+      else
+      {  /* no value (elemental set) is provided */
+         error(mpl, "no value for %s%s", set->name, format_tuple(mpl,
+            '[', tuple));
+      }
+      return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_set - evaluate elemental set assigned to set member.
+--
+-- This routine evaluates a reference to elemental set assigned to given
+-- member of specified model set and returns it on exit. */
+
+struct eval_set_info
+{     /* working info used by the routine eval_member_set */
+      SET *set;
+      /* model set */
+      TUPLE *tuple;
+      /* n-tuple, which defines set member */
+      MEMBER *memb;
+      /* normally this pointer is NULL; the routine uses this pointer
+         to check data provided in the data section, in which case it
+         points to a member currently checked; this check is performed
+         automatically only once when a reference to any member occurs
+         for the first time */
+      ELEMSET *refer;
+      /* evaluated reference to elemental set */
+};
+
+static void eval_set_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_set_info *info = _info;
+      if (info->memb != NULL)
+      {  /* checking call; check elemental set being assigned */
+         check_elem_set(mpl, info->set, info->memb->tuple,
+            info->memb->value.set);
+      }
+      else
+      {  /* normal call; evaluate member, which has given n-tuple */
+         info->refer = take_member_set(mpl, info->set, info->tuple);
+      }
+      return;
+}
+
+#if 1 /* 12/XII-2008 */
+static void saturate_set(MPL *mpl, SET *set)
+{     GADGET *gadget = set->gadget;
+      ELEMSET *data;
+      MEMBER *elem, *memb;
+      TUPLE *tuple, *work[20];
+      int i;
+      xprintf("Generating %s...\n", set->name);
+      eval_whole_set(mpl, gadget->set);
+      /* gadget set must have exactly one member */
+      xassert(gadget->set->array != NULL);
+      xassert(gadget->set->array->head != NULL);
+      xassert(gadget->set->array->head == gadget->set->array->tail);
+      data = gadget->set->array->head->value.set;
+      xassert(data->type == A_NONE);
+      xassert(data->dim == gadget->set->dimen);
+      /* walk thru all elements of the plain set */
+      for (elem = data->head; elem != NULL; elem = elem->next)
+      {  /* create a copy of n-tuple */
+         tuple = copy_tuple(mpl, elem->tuple);
+         /* rearrange component of the n-tuple */
+         for (i = 0; i < gadget->set->dimen; i++)
+            work[i] = NULL;
+         for (i = 0; tuple != NULL; tuple = tuple->next)
+            work[gadget->ind[i++]-1] = tuple;
+         xassert(i == gadget->set->dimen);
+         for (i = 0; i < gadget->set->dimen; i++)
+         {  xassert(work[i] != NULL);
+            work[i]->next = work[i+1];
+         }
+         /* construct subscript list from first set->dim components */
+         if (set->dim == 0)
+            tuple = NULL;
+         else
+            tuple = work[0], work[set->dim-1]->next = NULL;
+         /* find corresponding member of the set to be initialized */
+         memb = find_member(mpl, set->array, tuple);
+         if (memb == NULL)
+         {  /* not found; add new member to the set and assign it empty
+               elemental set */
+            memb = add_member(mpl, set->array, tuple);
+            memb->value.set = create_elemset(mpl, set->dimen);
+         }
+         else
+         {  /* found; free subscript list */
+            delete_tuple(mpl, tuple);
+         }
+         /* construct new n-tuple from rest set->dimen components */
+         tuple = work[set->dim];
+         xassert(set->dim + set->dimen == gadget->set->dimen);
+         work[gadget->set->dimen-1]->next = NULL;
+         /* and add it to the elemental set assigned to the member
+            (no check for duplicates is needed) */
+         add_tuple(mpl, memb->value.set, tuple);
+      }
+      /* the set has been saturated with data */
+      set->data = 1;
+      return;
+}
+#endif
+
+ELEMSET *eval_member_set      /* returns reference, not value */
+(     MPL *mpl,
+      SET *set,               /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates set member */
+      struct eval_set_info _info, *info = &_info;
+      xassert(set->dim == tuple_dimen(mpl, tuple));
+      info->set = set;
+      info->tuple = tuple;
+#if 1 /* 12/XII-2008 */
+      if (set->gadget != NULL && set->data == 0)
+      {  /* initialize the set with data from a plain set */
+         saturate_set(mpl, set);
+      }
+#endif
+      if (set->data == 1)
+      {  /* check data, which are provided in the data section, but not
+            checked yet */
+         /* save pointer to the last array member; note that during the
+            check new members may be added beyond the last member due to
+            references to the same parameter from default expression as
+            well as from expressions that define restricting supersets;
+            however, values assigned to the new members will be checked
+            by other routine, so we don't need to check them here */
+         MEMBER *tail = set->array->tail;
+         /* change the data status to prevent infinite recursive loop
+            due to references to the same set during the check */
+         set->data = 2;
+         /* check elemental sets assigned to array members in the data
+            section until the marked member has been reached */
+         for (info->memb = set->array->head; info->memb != NULL;
+            info->memb = info->memb->next)
+         {  if (eval_within_domain(mpl, set->domain, info->memb->tuple,
+               info, eval_set_func))
+               out_of_domain(mpl, set->name, info->memb->tuple);
+            if (info->memb == tail) break;
+         }
+         /* the check has been finished */
+      }
+      /* evaluate member, which has given n-tuple */
+      info->memb = NULL;
+      if (eval_within_domain(mpl, info->set->domain, info->tuple, info,
+         eval_set_func))
+      out_of_domain(mpl, set->name, info->tuple);
+      /* bring evaluated reference to the calling program */
+      return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_set - evaluate model set over entire domain.
+--
+-- This routine evaluates all members of specified model set over entire
+-- domain. */
+
+static int whole_set_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      SET *set = (SET *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, set->domain);
+      eval_member_set(mpl, set, tuple);
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_set(MPL *mpl, SET *set)
+{     loop_within_domain(mpl, set->domain, set, whole_set_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean set - clean model set.
+--
+-- This routine cleans specified model set that assumes deleting all
+-- stuff dynamically allocated during the generation phase. */
+
+void clean_set(MPL *mpl, SET *set)
+{     WITHIN *within;
+      MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, set->domain);
+      /* clean pseudo-code for computing supersets */
+      for (within = set->within; within != NULL; within = within->next)
+         clean_code(mpl, within->code);
+      /* clean pseudo-code for computing assigned value */
+      clean_code(mpl, set->assign);
+      /* clean pseudo-code for computing default value */
+      clean_code(mpl, set->option);
+      /* reset data status flag */
+      set->data = 0;
+      /* delete content array */
+      for (memb = set->array->head; memb != NULL; memb = memb->next)
+         delete_value(mpl, set->array->type, &memb->value);
+      delete_array(mpl, set->array), set->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *                      MODEL PARAMETERS                      * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- check_value_num - check numeric value assigned to parameter member.
+--
+-- This routine checks if numeric value being assigned to some member
+-- of specified numeric model parameter satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_value_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      double value
+)
+{     CONDITION *cond;
+      WITHIN *in;
+      int eqno;
+      /* the value must satisfy to the parameter type */
+      switch (par->type)
+      {  case A_NUMERIC:
+            break;
+         case A_INTEGER:
+            if (value != floor(value))
+               error(mpl, "%s%s = %.*g not integer", par->name,
+                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
+            break;
+         case A_BINARY:
+            if (!(value == 0.0 || value == 1.0))
+               error(mpl, "%s%s = %.*g not binary", par->name,
+                  format_tuple(mpl, '[', tuple), DBL_DIG, value);
+            break;
+         default:
+            xassert(par != par);
+      }
+      /* the value must satisfy to all specified conditions */
+      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
+         eqno++)
+      {  double bound;
+         char *rho;
+         xassert(cond->code != NULL);
+         bound = eval_numeric(mpl, cond->code);
+         switch (cond->rho)
+         {  case O_LT:
+               if (!(value < bound))
+               {  rho = "<";
+err:              error(mpl, "%s%s = %.*g not %s %.*g; see (%d)",
+                     par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
+                     value, rho, DBL_DIG, bound, eqno);
+               }
+               break;
+            case O_LE:
+               if (!(value <= bound)) { rho = "<="; goto err; }
+               break;
+            case O_EQ:
+               if (!(value == bound)) { rho = "="; goto err; }
+               break;
+            case O_GE:
+               if (!(value >= bound)) { rho = ">="; goto err; }
+               break;
+            case O_GT:
+               if (!(value > bound)) { rho = ">"; goto err; }
+               break;
+            case O_NE:
+               if (!(value != bound)) { rho = "<>"; goto err; }
+               break;
+            default:
+               xassert(cond != cond);
+         }
+      }
+      /* the value must be in all specified supersets */
+      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
+      {  TUPLE *dummy;
+         xassert(in->code != NULL);
+         xassert(in->code->dim == 1);
+         dummy = expand_tuple(mpl, create_tuple(mpl),
+            create_symbol_num(mpl, value));
+         if (!is_member(mpl, in->code, dummy))
+            error(mpl, "%s%s = %.*g not in specified set; see (%d)",
+               par->name, format_tuple(mpl, '[', tuple), DBL_DIG,
+               value, eqno);
+         delete_tuple(mpl, dummy);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_num - obtain num. value assigned to parameter member.
+--
+-- This routine obtains a numeric value assigned to member of specified
+-- numeric model parameter and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+double take_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      double value;
+      /* find member in the parameter array */
+      memb = find_member(mpl, par->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take its value */
+         value = memb->value.num;
+      }
+      else if (par->assign != NULL)
+      {  /* compute value using assignment expression */
+         value = eval_numeric(mpl, par->assign);
+add:     /* check that the value satisfies to all restrictions, assign
+            it to new member, and add the member to the array */
+         check_value_num(mpl, par, tuple, value);
+         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
+         memb->value.num = value;
+      }
+      else if (par->option != NULL)
+      {  /* compute default value */
+         value = eval_numeric(mpl, par->option);
+         goto add;
+      }
+      else if (par->defval != NULL)
+      {  /* take default value provided in the data section */
+         if (par->defval->str != NULL)
+            error(mpl, "cannot convert %s to floating-point number",
+               format_symbol(mpl, par->defval));
+         value = par->defval->num;
+         goto add;
+      }
+      else
+      {  /* no value is provided */
+         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
+            '[', tuple));
+      }
+      return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_num - evaluate num. value assigned to parameter member.
+--
+-- This routine evaluates a numeric value assigned to given member of
+-- specified numeric model parameter and returns it on exit. */
+
+struct eval_num_info
+{     /* working info used by the routine eval_member_num */
+      PARAMETER *par;
+      /* model parameter  */
+      TUPLE *tuple;
+      /* n-tuple, which defines parameter member */
+      MEMBER *memb;
+      /* normally this pointer is NULL; the routine uses this pointer
+         to check data provided in the data section, in which case it
+         points to a member currently checked; this check is performed
+         automatically only once when a reference to any member occurs
+         for the first time */
+      double value;
+      /* evaluated numeric value */
+};
+
+static void eval_num_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_num_info *info = _info;
+      if (info->memb != NULL)
+      {  /* checking call; check numeric value being assigned */
+         check_value_num(mpl, info->par, info->memb->tuple,
+            info->memb->value.num);
+      }
+      else
+      {  /* normal call; evaluate member, which has given n-tuple */
+         info->value = take_member_num(mpl, info->par, info->tuple);
+      }
+      return;
+}
+
+double eval_member_num
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates numeric parameter member */
+      struct eval_num_info _info, *info = &_info;
+      xassert(par->type == A_NUMERIC || par->type == A_INTEGER ||
+             par->type == A_BINARY);
+      xassert(par->dim == tuple_dimen(mpl, tuple));
+      info->par = par;
+      info->tuple = tuple;
+      if (par->data == 1)
+      {  /* check data, which are provided in the data section, but not
+            checked yet */
+         /* save pointer to the last array member; note that during the
+            check new members may be added beyond the last member due to
+            references to the same parameter from default expression as
+            well as from expressions that define restricting conditions;
+            however, values assigned to the new members will be checked
+            by other routine, so we don't need to check them here */
+         MEMBER *tail = par->array->tail;
+         /* change the data status to prevent infinite recursive loop
+            due to references to the same parameter during the check */
+         par->data = 2;
+         /* check values assigned to array members in the data section
+            until the marked member has been reached */
+         for (info->memb = par->array->head; info->memb != NULL;
+            info->memb = info->memb->next)
+         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
+               info, eval_num_func))
+               out_of_domain(mpl, par->name, info->memb->tuple);
+            if (info->memb == tail) break;
+         }
+         /* the check has been finished */
+      }
+      /* evaluate member, which has given n-tuple */
+      info->memb = NULL;
+      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
+         eval_num_func))
+         out_of_domain(mpl, par->name, info->tuple);
+      /* bring evaluated value to the calling program */
+      return info->value;
+}
+
+/*----------------------------------------------------------------------
+-- check_value_sym - check symbolic value assigned to parameter member.
+--
+-- This routine checks if symbolic value being assigned to some member
+-- of specified symbolic model parameter satisfies to all restrictions.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+void check_value_sym
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple,           /* not changed */
+      SYMBOL *value           /* not changed */
+)
+{     CONDITION *cond;
+      WITHIN *in;
+      int eqno;
+      /* the value must satisfy to all specified conditions */
+      for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next,
+         eqno++)
+      {  SYMBOL *bound;
+         char buf[255+1];
+         xassert(cond->code != NULL);
+         bound = eval_symbolic(mpl, cond->code);
+         switch (cond->rho)
+         {
+#if 1 /* 13/VIII-2008 */
+            case O_LT:
+               if (!(compare_symbols(mpl, value, bound) < 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not < %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+            case O_LE:
+               if (!(compare_symbols(mpl, value, bound) <= 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not <= %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+#endif
+            case O_EQ:
+               if (!(compare_symbols(mpl, value, bound) == 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not = %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+#if 1 /* 13/VIII-2008 */
+            case O_GE:
+               if (!(compare_symbols(mpl, value, bound) >= 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not >= %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+            case O_GT:
+               if (!(compare_symbols(mpl, value, bound) > 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not > %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+#endif
+            case O_NE:
+               if (!(compare_symbols(mpl, value, bound) != 0))
+               {  strcpy(buf, format_symbol(mpl, bound));
+                  xassert(strlen(buf) < sizeof(buf));
+                  error(mpl, "%s%s = %s not <> %s",
+                     par->name, format_tuple(mpl, '[', tuple),
+                     format_symbol(mpl, value), buf, eqno);
+               }
+               break;
+            default:
+               xassert(cond != cond);
+         }
+         delete_symbol(mpl, bound);
+      }
+      /* the value must be in all specified supersets */
+      for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++)
+      {  TUPLE *dummy;
+         xassert(in->code != NULL);
+         xassert(in->code->dim == 1);
+         dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl,
+            value));
+         if (!is_member(mpl, in->code, dummy))
+            error(mpl, "%s%s = %s not in specified set; see (%d)",
+               par->name, format_tuple(mpl, '[', tuple),
+               format_symbol(mpl, value), eqno);
+         delete_tuple(mpl, dummy);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- take_member_sym - obtain symb. value assigned to parameter member.
+--
+-- This routine obtains a symbolic value assigned to member of specified
+-- symbolic model parameter and returns it on exit.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+SYMBOL *take_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      SYMBOL *value;
+      /* find member in the parameter array */
+      memb = find_member(mpl, par->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take its value */
+         value = copy_symbol(mpl, memb->value.sym);
+      }
+      else if (par->assign != NULL)
+      {  /* compute value using assignment expression */
+         value = eval_symbolic(mpl, par->assign);
+add:     /* check that the value satisfies to all restrictions, assign
+            it to new member, and add the member to the array */
+         check_value_sym(mpl, par, tuple, value);
+         memb = add_member(mpl, par->array, copy_tuple(mpl, tuple));
+         memb->value.sym = copy_symbol(mpl, value);
+      }
+      else if (par->option != NULL)
+      {  /* compute default value */
+         value = eval_symbolic(mpl, par->option);
+         goto add;
+      }
+      else if (par->defval != NULL)
+      {  /* take default value provided in the data section */
+         value = copy_symbol(mpl, par->defval);
+         goto add;
+      }
+      else
+      {  /* no value is provided */
+         error(mpl, "no value for %s%s", par->name, format_tuple(mpl,
+            '[', tuple));
+      }
+      return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_sym - evaluate symb. value assigned to parameter member.
+--
+-- This routine evaluates a symbolic value assigned to given member of
+-- specified symbolic model parameter and returns it on exit. */
+
+struct eval_sym_info
+{     /* working info used by the routine eval_member_sym */
+      PARAMETER *par;
+      /* model parameter */
+      TUPLE *tuple;
+      /* n-tuple, which defines parameter member */
+      MEMBER *memb;
+      /* normally this pointer is NULL; the routine uses this pointer
+         to check data provided in the data section, in which case it
+         points to a member currently checked; this check is performed
+         automatically only once when a reference to any member occurs
+         for the first time */
+      SYMBOL *value;
+      /* evaluated symbolic value */
+};
+
+static void eval_sym_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_sym_info *info = _info;
+      if (info->memb != NULL)
+      {  /* checking call; check symbolic value being assigned */
+         check_value_sym(mpl, info->par, info->memb->tuple,
+            info->memb->value.sym);
+      }
+      else
+      {  /* normal call; evaluate member, which has given n-tuple */
+         info->value = take_member_sym(mpl, info->par, info->tuple);
+      }
+      return;
+}
+
+SYMBOL *eval_member_sym       /* returns value, not reference */
+(     MPL *mpl,
+      PARAMETER *par,         /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates symbolic parameter member */
+      struct eval_sym_info _info, *info = &_info;
+      xassert(par->type == A_SYMBOLIC);
+      xassert(par->dim == tuple_dimen(mpl, tuple));
+      info->par = par;
+      info->tuple = tuple;
+      if (par->data == 1)
+      {  /* check data, which are provided in the data section, but not
+            checked yet */
+         /* save pointer to the last array member; note that during the
+            check new members may be added beyond the last member due to
+            references to the same parameter from default expression as
+            well as from expressions that define restricting conditions;
+            however, values assigned to the new members will be checked
+            by other routine, so we don't need to check them here */
+         MEMBER *tail = par->array->tail;
+         /* change the data status to prevent infinite recursive loop
+            due to references to the same parameter during the check */
+         par->data = 2;
+         /* check values assigned to array members in the data section
+            until the marked member has been reached */
+         for (info->memb = par->array->head; info->memb != NULL;
+            info->memb = info->memb->next)
+         {  if (eval_within_domain(mpl, par->domain, info->memb->tuple,
+               info, eval_sym_func))
+               out_of_domain(mpl, par->name, info->memb->tuple);
+            if (info->memb == tail) break;
+         }
+         /* the check has been finished */
+      }
+      /* evaluate member, which has given n-tuple */
+      info->memb = NULL;
+      if (eval_within_domain(mpl, info->par->domain, info->tuple, info,
+         eval_sym_func))
+         out_of_domain(mpl, par->name, info->tuple);
+      /* bring evaluated value to the calling program */
+      return info->value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_par - evaluate model parameter over entire domain.
+--
+-- This routine evaluates all members of specified model parameter over
+-- entire domain. */
+
+static int whole_par_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      PARAMETER *par = (PARAMETER *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, par->domain);
+      switch (par->type)
+      {  case A_NUMERIC:
+         case A_INTEGER:
+         case A_BINARY:
+            eval_member_num(mpl, par, tuple);
+            break;
+         case A_SYMBOLIC:
+            delete_symbol(mpl, eval_member_sym(mpl, par, tuple));
+            break;
+         default:
+            xassert(par != par);
+      }
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_par(MPL *mpl, PARAMETER *par)
+{     loop_within_domain(mpl, par->domain, par, whole_par_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_parameter - clean model parameter.
+--
+-- This routine cleans specified model parameter that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_parameter(MPL *mpl, PARAMETER *par)
+{     CONDITION *cond;
+      WITHIN *in;
+      MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, par->domain);
+      /* clean pseudo-code for computing restricting conditions */
+      for (cond = par->cond; cond != NULL; cond = cond->next)
+         clean_code(mpl, cond->code);
+      /* clean pseudo-code for computing restricting supersets */
+      for (in = par->in; in != NULL; in = in->next)
+         clean_code(mpl, in->code);
+      /* clean pseudo-code for computing assigned value */
+      clean_code(mpl, par->assign);
+      /* clean pseudo-code for computing default value */
+      clean_code(mpl, par->option);
+      /* reset data status flag */
+      par->data = 0;
+      /* delete default symbolic value */
+      if (par->defval != NULL)
+         delete_symbol(mpl, par->defval), par->defval = NULL;
+      /* delete content array */
+      for (memb = par->array->head; memb != NULL; memb = memb->next)
+         delete_value(mpl, par->array->type, &memb->value);
+      delete_array(mpl, par->array), par->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *                      MODEL VARIABLES                       * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- take_member_var - obtain reference to elemental variable.
+--
+-- This routine obtains a reference to elemental variable assigned to
+-- given member of specified model variable and returns it on exit. If
+-- necessary, new elemental variable is created.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMVAR *take_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      ELEMVAR *refer;
+      /* find member in the variable array */
+      memb = find_member(mpl, var->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take the reference */
+         refer = memb->value.var;
+      }
+      else
+      {  /* member is referenced for the first time and therefore does
+            not exist; create new elemental variable, assign it to new
+            member, and add the member to the variable array */
+         memb = add_member(mpl, var->array, copy_tuple(mpl, tuple));
+         refer = (memb->value.var =
+            dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR)));
+         refer->j = 0;
+         refer->var = var;
+         refer->memb = memb;
+         /* compute lower bound */
+         if (var->lbnd == NULL)
+            refer->lbnd = 0.0;
+         else
+            refer->lbnd = eval_numeric(mpl, var->lbnd);
+         /* compute upper bound */
+         if (var->ubnd == NULL)
+            refer->ubnd = 0.0;
+         else if (var->ubnd == var->lbnd)
+            refer->ubnd = refer->lbnd;
+         else
+            refer->ubnd = eval_numeric(mpl, var->ubnd);
+         /* nullify working quantity */
+         refer->temp = 0.0;
+#if 1 /* 15/V-2010 */
+         /* solution has not been obtained by the solver yet */
+         refer->stat = 0;
+         refer->prim = refer->dual = 0.0;
+#endif
+      }
+      return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_var - evaluate reference to elemental variable.
+--
+-- This routine evaluates a reference to elemental variable assigned to
+-- member of specified model variable and returns it on exit. */
+
+struct eval_var_info
+{     /* working info used by the routine eval_member_var */
+      VARIABLE *var;
+      /* model variable */
+      TUPLE *tuple;
+      /* n-tuple, which defines variable member */
+      ELEMVAR *refer;
+      /* evaluated reference to elemental variable */
+};
+
+static void eval_var_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_var_info *info = _info;
+      info->refer = take_member_var(mpl, info->var, info->tuple);
+      return;
+}
+
+ELEMVAR *eval_member_var      /* returns reference */
+(     MPL *mpl,
+      VARIABLE *var,          /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates variable member */
+      struct eval_var_info _info, *info = &_info;
+      xassert(var->dim == tuple_dimen(mpl, tuple));
+      info->var = var;
+      info->tuple = tuple;
+      /* evaluate member, which has given n-tuple */
+      if (eval_within_domain(mpl, info->var->domain, info->tuple, info,
+         eval_var_func))
+         out_of_domain(mpl, var->name, info->tuple);
+      /* bring evaluated reference to the calling program */
+      return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_var - evaluate model variable over entire domain.
+--
+-- This routine evaluates all members of specified model variable over
+-- entire domain. */
+
+static int whole_var_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      VARIABLE *var = (VARIABLE *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, var->domain);
+      eval_member_var(mpl, var, tuple);
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_var(MPL *mpl, VARIABLE *var)
+{     loop_within_domain(mpl, var->domain, var, whole_var_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_variable - clean model variable.
+--
+-- This routine cleans specified model variable that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_variable(MPL *mpl, VARIABLE *var)
+{     MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, var->domain);
+      /* clean code for computing lower bound */
+      clean_code(mpl, var->lbnd);
+      /* clean code for computing upper bound */
+      if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd);
+      /* delete content array */
+      for (memb = var->array->head; memb != NULL; memb = memb->next)
+         dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR));
+      delete_array(mpl, var->array), var->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *              MODEL CONSTRAINTS AND OBJECTIVES              * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- take_member_con - obtain reference to elemental constraint.
+--
+-- This routine obtains a reference to elemental constraint assigned
+-- to given member of specified model constraint and returns it on exit.
+-- If necessary, new elemental constraint is created.
+--
+-- NOTE: This routine must not be called out of domain scope. */
+
+ELEMCON *take_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     MEMBER *memb;
+      ELEMCON *refer;
+      /* find member in the constraint array */
+      memb = find_member(mpl, con->array, tuple);
+      if (memb != NULL)
+      {  /* member exists, so just take the reference */
+         refer = memb->value.con;
+      }
+      else
+      {  /* member is referenced for the first time and therefore does
+            not exist; create new elemental constraint, assign it to new
+            member, and add the member to the constraint array */
+         memb = add_member(mpl, con->array, copy_tuple(mpl, tuple));
+         refer = (memb->value.con =
+            dmp_get_atom(mpl->elemcons, sizeof(ELEMCON)));
+         refer->i = 0;
+         refer->con = con;
+         refer->memb = memb;
+         /* compute linear form */
+         xassert(con->code != NULL);
+         refer->form = eval_formula(mpl, con->code);
+         /* compute lower and upper bounds */
+         if (con->lbnd == NULL && con->ubnd == NULL)
+         {  /* objective has no bounds */
+            double temp;
+            xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE);
+            /* carry the constant term to the right-hand side */
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = refer->ubnd = - temp;
+         }
+         else if (con->lbnd != NULL && con->ubnd == NULL)
+         {  /* constraint a * x + b >= c * y + d is transformed to the
+               standard form a * x - c * y >= d - b */
+            double temp;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = linear_comb(mpl,
+               +1.0, refer->form,
+               -1.0, eval_formula(mpl, con->lbnd));
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = - temp;
+            refer->ubnd = 0.0;
+         }
+         else if (con->lbnd == NULL && con->ubnd != NULL)
+         {  /* constraint a * x + b <= c * y + d is transformed to the
+               standard form a * x - c * y <= d - b */
+            double temp;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = linear_comb(mpl,
+               +1.0, refer->form,
+               -1.0, eval_formula(mpl, con->ubnd));
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = 0.0;
+            refer->ubnd = - temp;
+         }
+         else if (con->lbnd == con->ubnd)
+         {  /* constraint a * x + b = c * y + d is transformed to the
+               standard form a * x - c * y = d - b */
+            double temp;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = linear_comb(mpl,
+               +1.0, refer->form,
+               -1.0, eval_formula(mpl, con->lbnd));
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            refer->lbnd = refer->ubnd = - temp;
+         }
+         else
+         {  /* ranged constraint c <= a * x + b <= d is transformed to
+               the standard form c - b <= a * x <= d - b */
+            double temp, temp1, temp2;
+            xassert(con->type == A_CONSTRAINT);
+            refer->form = remove_constant(mpl, refer->form, &temp);
+            xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd),
+               &temp1) == NULL);
+            xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd),
+               &temp2) == NULL);
+            refer->lbnd = fp_sub(mpl, temp1, temp);
+            refer->ubnd = fp_sub(mpl, temp2, temp);
+         }
+#if 1 /* 15/V-2010 */
+         /* solution has not been obtained by the solver yet */
+         refer->stat = 0;
+         refer->prim = refer->dual = 0.0;
+#endif
+      }
+      return refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_member_con - evaluate reference to elemental constraint.
+--
+-- This routine evaluates a reference to elemental constraint assigned
+-- to member of specified model constraint and returns it on exit. */
+
+struct eval_con_info
+{     /* working info used by the routine eval_member_con */
+      CONSTRAINT *con;
+      /* model constraint */
+      TUPLE *tuple;
+      /* n-tuple, which defines constraint member */
+      ELEMCON *refer;
+      /* evaluated reference to elemental constraint */
+};
+
+static void eval_con_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine to work within domain scope */
+      struct eval_con_info *info = _info;
+      info->refer = take_member_con(mpl, info->con, info->tuple);
+      return;
+}
+
+ELEMCON *eval_member_con      /* returns reference */
+(     MPL *mpl,
+      CONSTRAINT *con,        /* not changed */
+      TUPLE *tuple            /* not changed */
+)
+{     /* this routine evaluates constraint member */
+      struct eval_con_info _info, *info = &_info;
+      xassert(con->dim == tuple_dimen(mpl, tuple));
+      info->con = con;
+      info->tuple = tuple;
+      /* evaluate member, which has given n-tuple */
+      if (eval_within_domain(mpl, info->con->domain, info->tuple, info,
+         eval_con_func))
+         out_of_domain(mpl, con->name, info->tuple);
+      /* bring evaluated reference to the calling program */
+      return info->refer;
+}
+
+/*----------------------------------------------------------------------
+-- eval_whole_con - evaluate model constraint over entire domain.
+--
+-- This routine evaluates all members of specified model constraint over
+-- entire domain. */
+
+static int whole_con_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      CONSTRAINT *con = (CONSTRAINT *)info;
+      TUPLE *tuple = get_domain_tuple(mpl, con->domain);
+      eval_member_con(mpl, con, tuple);
+      delete_tuple(mpl, tuple);
+      return 0;
+}
+
+void eval_whole_con(MPL *mpl, CONSTRAINT *con)
+{     loop_within_domain(mpl, con->domain, con, whole_con_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_constraint - clean model constraint.
+--
+-- This routine cleans specified model constraint that assumes deleting
+-- all stuff dynamically allocated during the generation phase. */
+
+void clean_constraint(MPL *mpl, CONSTRAINT *con)
+{     MEMBER *memb;
+      /* clean subscript domain */
+      clean_domain(mpl, con->domain);
+      /* clean code for computing main linear form */
+      clean_code(mpl, con->code);
+      /* clean code for computing lower bound */
+      clean_code(mpl, con->lbnd);
+      /* clean code for computing upper bound */
+      if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd);
+      /* delete content array */
+      for (memb = con->array->head; memb != NULL; memb = memb->next)
+      {  delete_formula(mpl, memb->value.con->form);
+         dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON));
+      }
+      delete_array(mpl, con->array), con->array = NULL;
+      return;
+}
+
+/**********************************************************************/
+/* * *                        PSEUDO-CODE                         * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- eval_numeric - evaluate pseudo-code to determine numeric value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- numeric value, which is returned on exit. */
+
+struct iter_num_info
+{     /* working info used by the routine iter_num_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      double value;
+      /* resultant value */
+};
+
+static int iter_num_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on numeric "integrand" within domain scope */
+      struct iter_num_info *info = _info;
+      double temp;
+      temp = eval_numeric(mpl, info->code->arg.loop.x);
+      switch (info->code->op)
+      {  case O_SUM:
+            /* summation over domain */
+            info->value = fp_add(mpl, info->value, temp);
+            break;
+         case O_PROD:
+            /* multiplication over domain */
+            info->value = fp_mul(mpl, info->value, temp);
+            break;
+         case O_MINIMUM:
+            /* minimum over domain */
+            if (info->value > temp) info->value = temp;
+            break;
+         case O_MAXIMUM:
+            /* maximum over domain */
+            if (info->value < temp) info->value = temp;
+            break;
+         default:
+            xassert(info != info);
+      }
+      return 0;
+}
+
+double eval_numeric(MPL *mpl, CODE *code)
+{     double value;
+      xassert(code != NULL);
+      xassert(code->type == A_NUMERIC);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = code->value.num;
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_NUMBER:
+            /* take floating-point number */
+            value = code->arg.num;
+            break;
+         case O_MEMNUM:
+            /* take member of numeric parameter */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.par.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               value = eval_member_num(mpl, code->arg.par.par, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_MEMVAR:
+            /* take computed value of elemental variable */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+#if 1 /* 15/V-2010 */
+               ELEMVAR *var;
+#endif
+               tuple = create_tuple(mpl);
+               for (e = code->arg.var.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+#if 0 /* 15/V-2010 */
+               value = eval_member_var(mpl, code->arg.var.var, tuple)
+                  ->value;
+#else
+               var = eval_member_var(mpl, code->arg.var.var, tuple);
+               switch (code->arg.var.suff)
+               {  case DOT_LB:
+                     if (var->var->lbnd == NULL)
+                        value = -DBL_MAX;
+                     else
+                        value = var->lbnd;
+                     break;
+                  case DOT_UB:
+                     if (var->var->ubnd == NULL)
+                        value = +DBL_MAX;
+                     else
+                        value = var->ubnd;
+                     break;
+                  case DOT_STATUS:
+                     value = var->stat;
+                     break;
+                  case DOT_VAL:
+                     value = var->prim;
+                     break;
+                  case DOT_DUAL:
+                     value = var->dual;
+                     break;
+                  default:
+                     xassert(code != code);
+               }
+#endif
+               delete_tuple(mpl, tuple);
+            }
+            break;
+#if 1 /* 15/V-2010 */
+         case O_MEMCON:
+            /* take computed value of elemental constraint */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               ELEMCON *con;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.con.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               con = eval_member_con(mpl, code->arg.con.con, tuple);
+               switch (code->arg.con.suff)
+               {  case DOT_LB:
+                     if (con->con->lbnd == NULL)
+                        value = -DBL_MAX;
+                     else
+                        value = con->lbnd;
+                     break;
+                  case DOT_UB:
+                     if (con->con->ubnd == NULL)
+                        value = +DBL_MAX;
+                     else
+                        value = con->ubnd;
+                     break;
+                  case DOT_STATUS:
+                     value = con->stat;
+                     break;
+                  case DOT_VAL:
+                     value = con->prim;
+                     break;
+                  case DOT_DUAL:
+                     value = con->dual;
+                     break;
+                  default:
+                     xassert(code != code);
+               }
+               delete_tuple(mpl, tuple);
+            }
+            break;
+#endif
+         case O_IRAND224:
+            /* pseudo-random in [0, 2^24-1] */
+            value = fp_irand224(mpl);
+            break;
+         case O_UNIFORM01:
+            /* pseudo-random in [0, 1) */
+            value = fp_uniform01(mpl);
+            break;
+         case O_NORMAL01:
+            /* gaussian random, mu = 0, sigma = 1 */
+            value = fp_normal01(mpl);
+            break;
+         case O_GMTIME:
+            /* current calendar time */
+            value = fn_gmtime(mpl);
+            break;
+         case O_CVTNUM:
+            /* conversion to numeric */
+            {  SYMBOL *sym;
+               sym = eval_symbolic(mpl, code->arg.arg.x);
+#if 0 /* 23/XI-2008 */
+               if (sym->str != NULL)
+                  error(mpl, "cannot convert %s to floating-point numbe"
+                     "r", format_symbol(mpl, sym));
+               value = sym->num;
+#else
+               if (sym->str == NULL)
+                  value = sym->num;
+               else
+               {  if (str2num(sym->str, &value))
+                     error(mpl, "cannot convert %s to floating-point nu"
+                        "mber", format_symbol(mpl, sym));
+               }
+#endif
+               delete_symbol(mpl, sym);
+            }
+            break;
+         case O_PLUS:
+            /* unary plus */
+            value = + eval_numeric(mpl, code->arg.arg.x);
+            break;
+         case O_MINUS:
+            /* unary minus */
+            value = - eval_numeric(mpl, code->arg.arg.x);
+            break;
+         case O_ABS:
+            /* absolute value */
+            value = fabs(eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_CEIL:
+            /* round upward ("ceiling of x") */
+            value = ceil(eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_FLOOR:
+            /* round downward ("floor of x") */
+            value = floor(eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_EXP:
+            /* base-e exponential */
+            value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_LOG:
+            /* natural logarithm */
+            value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_LOG10:
+            /* common (decimal) logarithm */
+            value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_SQRT:
+            /* square root */
+            value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_SIN:
+            /* trigonometric sine */
+            value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_COS:
+            /* trigonometric cosine */
+            value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_ATAN:
+            /* trigonometric arctangent (one argument) */
+            value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x));
+            break;
+         case O_ATAN2:
+            /* trigonometric arctangent (two arguments) */
+            value = fp_atan2(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_ROUND:
+            /* round to nearest integer */
+            value = fp_round(mpl,
+               eval_numeric(mpl, code->arg.arg.x), 0.0);
+            break;
+         case O_ROUND2:
+            /* round to n fractional digits */
+            value = fp_round(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_TRUNC:
+            /* truncate to nearest integer */
+            value = fp_trunc(mpl,
+               eval_numeric(mpl, code->arg.arg.x), 0.0);
+            break;
+         case O_TRUNC2:
+            /* truncate to n fractional digits */
+            value = fp_trunc(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_ADD:
+            /* addition */
+            value = fp_add(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_SUB:
+            /* subtraction */
+            value = fp_sub(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_LESS:
+            /* non-negative subtraction */
+            value = fp_less(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_MUL:
+            /* multiplication */
+            value = fp_mul(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_DIV:
+            /* division */
+            value = fp_div(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_IDIV:
+            /* quotient of exact division */
+            value = fp_idiv(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_MOD:
+            /* remainder of exact division */
+            value = fp_mod(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_POWER:
+            /* exponentiation (raise to power) */
+            value = fp_power(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_UNIFORM:
+            /* pseudo-random in [a, b) */
+            value = fp_uniform(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_NORMAL:
+            /* gaussian random, given mu and sigma */
+            value = fp_normal(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y));
+            break;
+         case O_CARD:
+            {  ELEMSET *set;
+               set = eval_elemset(mpl, code->arg.arg.x);
+               value = set->size;
+               delete_array(mpl, set);
+            }
+            break;
+         case O_LENGTH:
+            {  SYMBOL *sym;
+               char str[MAX_LENGTH+1];
+               sym = eval_symbolic(mpl, code->arg.arg.x);
+               if (sym->str == NULL)
+                  sprintf(str, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, str);
+               delete_symbol(mpl, sym);
+               value = strlen(str);
+            }
+            break;
+         case O_STR2TIME:
+            {  SYMBOL *sym;
+               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
+               sym = eval_symbolic(mpl, code->arg.arg.x);
+               if (sym->str == NULL)
+                  sprintf(str, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, str);
+               delete_symbol(mpl, sym);
+               sym = eval_symbolic(mpl, code->arg.arg.y);
+               if (sym->str == NULL)
+                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, fmt);
+               delete_symbol(mpl, sym);
+               value = fn_str2time(mpl, str, fmt);
+            }
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_numeric(mpl, code->arg.arg.y);
+            else if (code->arg.arg.z == NULL)
+               value = 0.0;
+            else
+               value = eval_numeric(mpl, code->arg.arg.z);
+            break;
+         case O_MIN:
+            /* minimal value (n-ary) */
+            {  ARG_LIST *e;
+               double temp;
+               value = +DBL_MAX;
+               for (e = code->arg.list; e != NULL; e = e->next)
+               {  temp = eval_numeric(mpl, e->x);
+                  if (value > temp) value = temp;
+               }
+            }
+            break;
+         case O_MAX:
+            /* maximal value (n-ary) */
+            {  ARG_LIST *e;
+               double temp;
+               value = -DBL_MAX;
+               for (e = code->arg.list; e != NULL; e = e->next)
+               {  temp = eval_numeric(mpl, e->x);
+                  if (value < temp) value = temp;
+               }
+            }
+            break;
+         case O_SUM:
+            /* summation over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = 0.0;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               value = info->value;
+            }
+            break;
+         case O_PROD:
+            /* multiplication over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = 1.0;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               value = info->value;
+            }
+            break;
+         case O_MINIMUM:
+            /* minimum over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = +DBL_MAX;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               if (info->value == +DBL_MAX)
+                  error(mpl, "min{} over empty set; result undefined");
+               value = info->value;
+            }
+            break;
+         case O_MAXIMUM:
+            /* maximum over domain */
+            {  struct iter_num_info _info, *info = &_info;
+               info->code = code;
+               info->value = -DBL_MAX;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_num_func);
+               if (info->value == -DBL_MAX)
+                  error(mpl, "max{} over empty set; result undefined");
+               value = info->value;
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.num = value;
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_symbolic - evaluate pseudo-code to determine symbolic value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- symbolic value, which is returned on exit. */
+
+SYMBOL *eval_symbolic(MPL *mpl, CODE *code)
+{     SYMBOL *value;
+      xassert(code != NULL);
+      xassert(code->type == A_SYMBOLIC);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_symbol(mpl, code->value.sym);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_STRING:
+            /* take character string */
+            value = create_symbol_str(mpl, create_string(mpl,
+               code->arg.str));
+            break;
+         case O_INDEX:
+            /* take dummy index */
+            xassert(code->arg.index.slot->value != NULL);
+            value = copy_symbol(mpl, code->arg.index.slot->value);
+            break;
+         case O_MEMSYM:
+            /* take member of symbolic parameter */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.par.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               value = eval_member_sym(mpl, code->arg.par.par, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_CVTSYM:
+            /* conversion to symbolic */
+            value = create_symbol_num(mpl, eval_numeric(mpl,
+               code->arg.arg.x));
+            break;
+         case O_CONCAT:
+            /* concatenation */
+            value = concat_symbols(mpl,
+               eval_symbolic(mpl, code->arg.arg.x),
+               eval_symbolic(mpl, code->arg.arg.y));
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_symbolic(mpl, code->arg.arg.y);
+            else if (code->arg.arg.z == NULL)
+               value = create_symbol_num(mpl, 0.0);
+            else
+               value = eval_symbolic(mpl, code->arg.arg.z);
+            break;
+         case O_SUBSTR:
+         case O_SUBSTR3:
+            {  double pos, len;
+               char str[MAX_LENGTH+1];
+               value = eval_symbolic(mpl, code->arg.arg.x);
+               if (value->str == NULL)
+                  sprintf(str, "%.*g", DBL_DIG, value->num);
+               else
+                  fetch_string(mpl, value->str, str);
+               delete_symbol(mpl, value);
+               if (code->op == O_SUBSTR)
+               {  pos = eval_numeric(mpl, code->arg.arg.y);
+                  if (pos != floor(pos))
+                     error(mpl, "substr('...', %.*g); non-integer secon"
+                        "d argument", DBL_DIG, pos);
+                  if (pos < 1 || pos > strlen(str) + 1)
+                     error(mpl, "substr('...', %.*g); substring out of "
+                        "range", DBL_DIG, pos);
+               }
+               else
+               {  pos = eval_numeric(mpl, code->arg.arg.y);
+                  len = eval_numeric(mpl, code->arg.arg.z);
+                  if (pos != floor(pos) || len != floor(len))
+                     error(mpl, "substr('...', %.*g, %.*g); non-integer"
+                        " second and/or third argument", DBL_DIG, pos,
+                        DBL_DIG, len);
+                  if (pos < 1 || len < 0 || pos + len > strlen(str) + 1)
+                     error(mpl, "substr('...', %.*g, %.*g); substring o"
+                        "ut of range", DBL_DIG, pos, DBL_DIG, len);
+                  str[(int)pos + (int)len - 1] = '\0';
+               }
+               value = create_symbol_str(mpl, create_string(mpl, str +
+                  (int)pos - 1));
+            }
+            break;
+         case O_TIME2STR:
+            {  double num;
+               SYMBOL *sym;
+               char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1];
+               num = eval_numeric(mpl, code->arg.arg.x);
+               sym = eval_symbolic(mpl, code->arg.arg.y);
+               if (sym->str == NULL)
+                  sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+               else
+                  fetch_string(mpl, sym->str, fmt);
+               delete_symbol(mpl, sym);
+               fn_time2str(mpl, str, num, fmt);
+               value = create_symbol_str(mpl, create_string(mpl, str));
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.sym = copy_symbol(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_logical - evaluate pseudo-code to determine logical value.
+--
+-- This routine evaluates specified pseudo-code to determine resultant
+-- logical value, which is returned on exit. */
+
+struct iter_log_info
+{     /* working info used by the routine iter_log_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      int value;
+      /* resultant value */
+};
+
+static int iter_log_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on logical "integrand" within domain scope */
+      struct iter_log_info *info = _info;
+      int ret = 0;
+      switch (info->code->op)
+      {  case O_FORALL:
+            /* conjunction over domain */
+            info->value &= eval_logical(mpl, info->code->arg.loop.x);
+            if (!info->value) ret = 1;
+            break;
+         case O_EXISTS:
+            /* disjunction over domain */
+            info->value |= eval_logical(mpl, info->code->arg.loop.x);
+            if (info->value) ret = 1;
+            break;
+         default:
+            xassert(info != info);
+      }
+      return ret;
+}
+
+int eval_logical(MPL *mpl, CODE *code)
+{     int value;
+      xassert(code->type == A_LOGICAL);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = code->value.bit;
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_CVTLOG:
+            /* conversion to logical */
+            value = (eval_numeric(mpl, code->arg.arg.x) != 0.0);
+            break;
+         case O_NOT:
+            /* negation (logical "not") */
+            value = !eval_logical(mpl, code->arg.arg.x);
+            break;
+         case O_LT:
+            /* comparison on 'less than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) <
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) <
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) < 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_LE:
+            /* comparison on 'not greater than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) <=
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) <=
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) <= 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_EQ:
+            /* comparison on 'equal to' */
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) ==
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) == 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+            break;
+         case O_GE:
+            /* comparison on 'not less than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) >=
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) >=
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) >= 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_GT:
+            /* comparison on 'greater than' */
+#if 0 /* 02/VIII-2008 */
+            value = (eval_numeric(mpl, code->arg.arg.x) >
+                     eval_numeric(mpl, code->arg.arg.y));
+#else
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) >
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) > 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+#endif
+            break;
+         case O_NE:
+            /* comparison on 'not equal to' */
+            xassert(code->arg.arg.x != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+               value = (eval_numeric(mpl, code->arg.arg.x) !=
+                        eval_numeric(mpl, code->arg.arg.y));
+            else
+            {  SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x);
+               SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y);
+               value = (compare_symbols(mpl, sym1, sym2) != 0);
+               delete_symbol(mpl, sym1);
+               delete_symbol(mpl, sym2);
+            }
+            break;
+         case O_AND:
+            /* conjunction (logical "and") */
+            value = eval_logical(mpl, code->arg.arg.x) &&
+                    eval_logical(mpl, code->arg.arg.y);
+            break;
+         case O_OR:
+            /* disjunction (logical "or") */
+            value = eval_logical(mpl, code->arg.arg.x) ||
+                    eval_logical(mpl, code->arg.arg.y);
+            break;
+         case O_IN:
+            /* test on 'x in Y' */
+            {  TUPLE *tuple;
+               tuple = eval_tuple(mpl, code->arg.arg.x);
+               value = is_member(mpl, code->arg.arg.y, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_NOTIN:
+            /* test on 'x not in Y' */
+            {  TUPLE *tuple;
+               tuple = eval_tuple(mpl, code->arg.arg.x);
+               value = !is_member(mpl, code->arg.arg.y, tuple);
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_WITHIN:
+            /* test on 'X within Y' */
+            {  ELEMSET *set;
+               MEMBER *memb;
+               set = eval_elemset(mpl, code->arg.arg.x);
+               value = 1;
+               for (memb = set->head; memb != NULL; memb = memb->next)
+               {  if (!is_member(mpl, code->arg.arg.y, memb->tuple))
+                  {  value = 0;
+                     break;
+                  }
+               }
+               delete_elemset(mpl, set);
+            }
+            break;
+         case O_NOTWITHIN:
+            /* test on 'X not within Y' */
+            {  ELEMSET *set;
+               MEMBER *memb;
+               set = eval_elemset(mpl, code->arg.arg.x);
+               value = 1;
+               for (memb = set->head; memb != NULL; memb = memb->next)
+               {  if (is_member(mpl, code->arg.arg.y, memb->tuple))
+                  {  value = 0;
+                     break;
+                  }
+               }
+               delete_elemset(mpl, set);
+            }
+            break;
+         case O_FORALL:
+            /* conjunction (A-quantification) */
+            {  struct iter_log_info _info, *info = &_info;
+               info->code = code;
+               info->value = 1;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_log_func);
+               value = info->value;
+            }
+            break;
+         case O_EXISTS:
+            /* disjunction (E-quantification) */
+            {  struct iter_log_info _info, *info = &_info;
+               info->code = code;
+               info->value = 0;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_log_func);
+               value = info->value;
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.bit = value;
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_tuple - evaluate pseudo-code to construct n-tuple.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- n-tuple, which is returned on exit. */
+
+TUPLE *eval_tuple(MPL *mpl, CODE *code)
+{     TUPLE *value;
+      xassert(code != NULL);
+      xassert(code->type == A_TUPLE);
+      xassert(code->dim > 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_tuple(mpl, code->value.tuple);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_TUPLE:
+            /* make n-tuple */
+            {  ARG_LIST *e;
+               value = create_tuple(mpl);
+               for (e = code->arg.list; e != NULL; e = e->next)
+                  value = expand_tuple(mpl, value, eval_symbolic(mpl,
+                     e->x));
+            }
+            break;
+         case O_CVTTUP:
+            /* convert to 1-tuple */
+            value = expand_tuple(mpl, create_tuple(mpl),
+               eval_symbolic(mpl, code->arg.arg.x));
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.tuple = copy_tuple(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_elemset - evaluate pseudo-code to construct elemental set.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- elemental set, which is returned on exit. */
+
+struct iter_set_info
+{     /* working info used by the routine iter_set_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      ELEMSET *value;
+      /* resultant value */
+};
+
+static int iter_set_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on n-tuple "integrand" within domain scope */
+      struct iter_set_info *info = _info;
+      TUPLE *tuple;
+      switch (info->code->op)
+      {  case O_SETOF:
+            /* compute next n-tuple and add it to the set; in this case
+               duplicate n-tuples are silently ignored */
+            tuple = eval_tuple(mpl, info->code->arg.loop.x);
+            if (find_tuple(mpl, info->value, tuple) == NULL)
+               add_tuple(mpl, info->value, tuple);
+            else
+               delete_tuple(mpl, tuple);
+            break;
+         case O_BUILD:
+            /* construct next n-tuple using current values assigned to
+               *free* dummy indices as its components and add it to the
+               set; in this case duplicate n-tuples cannot appear */
+            add_tuple(mpl, info->value, get_domain_tuple(mpl,
+               info->code->arg.loop.domain));
+            break;
+         default:
+            xassert(info != info);
+      }
+      return 0;
+}
+
+ELEMSET *eval_elemset(MPL *mpl, CODE *code)
+{     ELEMSET *value;
+      xassert(code != NULL);
+      xassert(code->type == A_ELEMSET);
+      xassert(code->dim > 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_elemset(mpl, code->value.set);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_MEMSET:
+            /* take member of set */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.set.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+               value = copy_elemset(mpl,
+                  eval_member_set(mpl, code->arg.set.set, tuple));
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_MAKE:
+            /* make elemental set of n-tuples */
+            {  ARG_LIST *e;
+               value = create_elemset(mpl, code->dim);
+               for (e = code->arg.list; e != NULL; e = e->next)
+                  check_then_add(mpl, value, eval_tuple(mpl, e->x));
+            }
+            break;
+         case O_UNION:
+            /* union of two elemental sets */
+            value = set_union(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_DIFF:
+            /* difference between two elemental sets */
+            value = set_diff(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_SYMDIFF:
+            /* symmetric difference between two elemental sets */
+            value = set_symdiff(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_INTER:
+            /* intersection of two elemental sets */
+            value = set_inter(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_CROSS:
+            /* cross (Cartesian) product of two elemental sets */
+            value = set_cross(mpl,
+               eval_elemset(mpl, code->arg.arg.x),
+               eval_elemset(mpl, code->arg.arg.y));
+            break;
+         case O_DOTS:
+            /* build "arithmetic" elemental set */
+            value = create_arelset(mpl,
+               eval_numeric(mpl, code->arg.arg.x),
+               eval_numeric(mpl, code->arg.arg.y),
+               code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl,
+                  code->arg.arg.z));
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_elemset(mpl, code->arg.arg.y);
+            else
+               value = eval_elemset(mpl, code->arg.arg.z);
+            break;
+         case O_SETOF:
+            /* compute elemental set */
+            {  struct iter_set_info _info, *info = &_info;
+               info->code = code;
+               info->value = create_elemset(mpl, code->dim);
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_set_func);
+               value = info->value;
+            }
+            break;
+         case O_BUILD:
+            /* build elemental set identical to domain set */
+            {  struct iter_set_info _info, *info = &_info;
+               info->code = code;
+               info->value = create_elemset(mpl, code->dim);
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_set_func);
+               value = info->value;
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.set = copy_elemset(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- is_member - check if n-tuple is in set specified by pseudo-code.
+--
+-- This routine checks if given n-tuple is a member of elemental set
+-- specified in the form of pseudo-code (i.e. by expression).
+--
+-- The n-tuple may have more components that dimension of the elemental
+-- set, in which case the extra components are ignored. */
+
+static void null_func(MPL *mpl, void *info)
+{     /* this is dummy routine used to enter the domain scope */
+      xassert(mpl == mpl);
+      xassert(info == NULL);
+      return;
+}
+
+int is_member(MPL *mpl, CODE *code, TUPLE *tuple)
+{     int value;
+      xassert(code != NULL);
+      xassert(code->type == A_ELEMSET);
+      xassert(code->dim > 0);
+      xassert(tuple != NULL);
+      switch (code->op)
+      {  case O_MEMSET:
+            /* check if given n-tuple is member of elemental set, which
+               is assigned to member of model set */
+            {  ARG_LIST *e;
+               TUPLE *temp;
+               ELEMSET *set;
+               /* evaluate reference to elemental set */
+               temp = create_tuple(mpl);
+               for (e = code->arg.set.list; e != NULL; e = e->next)
+                  temp = expand_tuple(mpl, temp, eval_symbolic(mpl,
+                     e->x));
+               set = eval_member_set(mpl, code->arg.set.set, temp);
+               delete_tuple(mpl, temp);
+               /* check if the n-tuple is contained in the set array */
+               temp = build_subtuple(mpl, tuple, set->dim);
+               value = (find_tuple(mpl, set, temp) != NULL);
+               delete_tuple(mpl, temp);
+            }
+            break;
+         case O_MAKE:
+            /* check if given n-tuple is member of literal set */
+            {  ARG_LIST *e;
+               TUPLE *temp, *that;
+               value = 0;
+               temp = build_subtuple(mpl, tuple, code->dim);
+               for (e = code->arg.list; e != NULL; e = e->next)
+               {  that = eval_tuple(mpl, e->x);
+                  value = (compare_tuples(mpl, temp, that) == 0);
+                  delete_tuple(mpl, that);
+                  if (value) break;
+               }
+               delete_tuple(mpl, temp);
+            }
+            break;
+         case O_UNION:
+            value = is_member(mpl, code->arg.arg.x, tuple) ||
+                    is_member(mpl, code->arg.arg.y, tuple);
+            break;
+         case O_DIFF:
+            value = is_member(mpl, code->arg.arg.x, tuple) &&
+                   !is_member(mpl, code->arg.arg.y, tuple);
+            break;
+         case O_SYMDIFF:
+            {  int in1 = is_member(mpl, code->arg.arg.x, tuple);
+               int in2 = is_member(mpl, code->arg.arg.y, tuple);
+               value = (in1 && !in2) || (!in1 && in2);
+            }
+            break;
+         case O_INTER:
+            value = is_member(mpl, code->arg.arg.x, tuple) &&
+                    is_member(mpl, code->arg.arg.y, tuple);
+            break;
+         case O_CROSS:
+            {  int j;
+               value = is_member(mpl, code->arg.arg.x, tuple);
+               if (value)
+               {  for (j = 1; j <= code->arg.arg.x->dim; j++)
+                  {  xassert(tuple != NULL);
+                     tuple = tuple->next;
+                  }
+                  value = is_member(mpl, code->arg.arg.y, tuple);
+               }
+            }
+            break;
+         case O_DOTS:
+            /* check if given 1-tuple is member of "arithmetic" set */
+            {  int j;
+               double x, t0, tf, dt;
+               xassert(code->dim == 1);
+               /* compute "parameters" of the "arithmetic" set */
+               t0 = eval_numeric(mpl, code->arg.arg.x);
+               tf = eval_numeric(mpl, code->arg.arg.y);
+               if (code->arg.arg.z == NULL)
+                  dt = 1.0;
+               else
+                  dt = eval_numeric(mpl, code->arg.arg.z);
+               /* make sure the parameters are correct */
+               arelset_size(mpl, t0, tf, dt);
+               /* if component of 1-tuple is symbolic, not numeric, the
+                  1-tuple cannot be member of "arithmetic" set */
+               xassert(tuple->sym != NULL);
+               if (tuple->sym->str != NULL)
+               {  value = 0;
+                  break;
+               }
+               /* determine numeric value of the component */
+               x = tuple->sym->num;
+               /* if the component value is out of the set range, the
+                  1-tuple is not in the set */
+               if (dt > 0.0 && !(t0 <= x && x <= tf) ||
+                   dt < 0.0 && !(tf <= x && x <= t0))
+               {  value = 0;
+                  break;
+               }
+               /* estimate ordinal number of the 1-tuple in the set */
+               j = (int)(((x - t0) / dt) + 0.5) + 1;
+               /* perform the main check */
+               value = (arelset_member(mpl, t0, tf, dt, j) == x);
+            }
+            break;
+         case O_FORK:
+            /* check if given n-tuple is member of conditional set */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = is_member(mpl, code->arg.arg.y, tuple);
+            else
+               value = is_member(mpl, code->arg.arg.z, tuple);
+            break;
+         case O_SETOF:
+            /* check if given n-tuple is member of computed set */
+            /* it is not clear how to efficiently perform the check not
+               computing the entire elemental set :+( */
+            error(mpl, "implementation restriction; in/within setof{} n"
+               "ot allowed");
+            break;
+         case O_BUILD:
+            /* check if given n-tuple is member of domain set */
+            {  TUPLE *temp;
+               temp = build_subtuple(mpl, tuple, code->dim);
+               /* try to enter the domain scope; if it is successful,
+                  the n-tuple is in the domain set */
+               value = (eval_within_domain(mpl, code->arg.loop.domain,
+                  temp, NULL, null_func) == 0);
+               delete_tuple(mpl, temp);
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      return value;
+}
+
+/*----------------------------------------------------------------------
+-- eval_formula - evaluate pseudo-code to construct linear form.
+--
+-- This routine evaluates specified pseudo-code to construct resultant
+-- linear form, which is returned on exit. */
+
+struct iter_form_info
+{     /* working info used by the routine iter_form_func */
+      CODE *code;
+      /* pseudo-code for iterated operation to be performed */
+      FORMULA *value;
+      /* resultant value */
+      FORMULA *tail;
+      /* pointer to the last term */
+};
+
+static int iter_form_func(MPL *mpl, void *_info)
+{     /* this is auxiliary routine used to perform iterated operation
+         on linear form "integrand" within domain scope */
+      struct iter_form_info *info = _info;
+      switch (info->code->op)
+      {  case O_SUM:
+            /* summation over domain */
+#if 0
+            info->value =
+               linear_comb(mpl,
+                  +1.0, info->value,
+                  +1.0, eval_formula(mpl, info->code->arg.loop.x));
+#else
+            /* the routine linear_comb needs to look through all terms
+               of both linear forms to reduce identical terms, so using
+               it here is not a good idea (for example, evaluation of
+               sum{i in 1..n} x[i] required quadratic time); the better
+               idea is to gather all terms of the integrand in one list
+               and reduce identical terms only once after all terms of
+               the resultant linear form have been evaluated */
+            {  FORMULA *form, *term;
+               form = eval_formula(mpl, info->code->arg.loop.x);
+               if (info->value == NULL)
+               {  xassert(info->tail == NULL);
+                  info->value = form;
+               }
+               else
+               {  xassert(info->tail != NULL);
+                  info->tail->next = form;
+               }
+               for (term = form; term != NULL; term = term->next)
+                  info->tail = term;
+            }
+#endif
+            break;
+         default:
+            xassert(info != info);
+      }
+      return 0;
+}
+
+FORMULA *eval_formula(MPL *mpl, CODE *code)
+{     FORMULA *value;
+      xassert(code != NULL);
+      xassert(code->type == A_FORMULA);
+      xassert(code->dim == 0);
+      /* if the operation has a side effect, invalidate and delete the
+         resultant value */
+      if (code->vflag && code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* if resultant value is valid, no evaluation is needed */
+      if (code->valid)
+      {  value = copy_formula(mpl, code->value.form);
+         goto done;
+      }
+      /* evaluate pseudo-code recursively */
+      switch (code->op)
+      {  case O_MEMVAR:
+            /* take member of variable */
+            {  TUPLE *tuple;
+               ARG_LIST *e;
+               tuple = create_tuple(mpl);
+               for (e = code->arg.var.list; e != NULL; e = e->next)
+                  tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl,
+                     e->x));
+#if 1 /* 15/V-2010 */
+               xassert(code->arg.var.suff == DOT_NONE);
+#endif
+               value = single_variable(mpl,
+                  eval_member_var(mpl, code->arg.var.var, tuple));
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case O_CVTLFM:
+            /* convert to linear form */
+            value = constant_term(mpl, eval_numeric(mpl,
+               code->arg.arg.x));
+            break;
+         case O_PLUS:
+            /* unary plus */
+            value = linear_comb(mpl,
+                0.0, constant_term(mpl, 0.0),
+               +1.0, eval_formula(mpl, code->arg.arg.x));
+            break;
+         case O_MINUS:
+            /* unary minus */
+            value = linear_comb(mpl,
+                0.0, constant_term(mpl, 0.0),
+               -1.0, eval_formula(mpl, code->arg.arg.x));
+            break;
+         case O_ADD:
+            /* addition */
+            value = linear_comb(mpl,
+               +1.0, eval_formula(mpl, code->arg.arg.x),
+               +1.0, eval_formula(mpl, code->arg.arg.y));
+            break;
+         case O_SUB:
+            /* subtraction */
+            value = linear_comb(mpl,
+               +1.0, eval_formula(mpl, code->arg.arg.x),
+               -1.0, eval_formula(mpl, code->arg.arg.y));
+            break;
+         case O_MUL:
+            /* multiplication */
+            xassert(code->arg.arg.x != NULL);
+            xassert(code->arg.arg.y != NULL);
+            if (code->arg.arg.x->type == A_NUMERIC)
+            {  xassert(code->arg.arg.y->type == A_FORMULA);
+               value = linear_comb(mpl,
+                  eval_numeric(mpl, code->arg.arg.x),
+                  eval_formula(mpl, code->arg.arg.y),
+                  0.0, constant_term(mpl, 0.0));
+            }
+            else
+            {  xassert(code->arg.arg.x->type == A_FORMULA);
+               xassert(code->arg.arg.y->type == A_NUMERIC);
+               value = linear_comb(mpl,
+                  eval_numeric(mpl, code->arg.arg.y),
+                  eval_formula(mpl, code->arg.arg.x),
+                  0.0, constant_term(mpl, 0.0));
+            }
+            break;
+         case O_DIV:
+            /* division */
+            value = linear_comb(mpl,
+               fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)),
+               eval_formula(mpl, code->arg.arg.x),
+               0.0, constant_term(mpl, 0.0));
+            break;
+         case O_FORK:
+            /* if-then-else */
+            if (eval_logical(mpl, code->arg.arg.x))
+               value = eval_formula(mpl, code->arg.arg.y);
+            else if (code->arg.arg.z == NULL)
+               value = constant_term(mpl, 0.0);
+            else
+               value = eval_formula(mpl, code->arg.arg.z);
+            break;
+         case O_SUM:
+            /* summation over domain */
+            {  struct iter_form_info _info, *info = &_info;
+               info->code = code;
+               info->value = constant_term(mpl, 0.0);
+               info->tail = NULL;
+               loop_within_domain(mpl, code->arg.loop.domain, info,
+                  iter_form_func);
+               value = reduce_terms(mpl, info->value);
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      /* save resultant value */
+      xassert(!code->valid);
+      code->valid = 1;
+      code->value.form = copy_formula(mpl, value);
+done: return value;
+}
+
+/*----------------------------------------------------------------------
+-- clean_code - clean pseudo-code.
+--
+-- This routine recursively cleans specified pseudo-code that assumes
+-- deleting all temporary resultant values. */
+
+void clean_code(MPL *mpl, CODE *code)
+{     ARG_LIST *e;
+      /* if no pseudo-code is specified, do nothing */
+      if (code == NULL) goto done;
+      /* if resultant value is valid (exists), delete it */
+      if (code->valid)
+      {  code->valid = 0;
+         delete_value(mpl, code->type, &code->value);
+      }
+      /* recursively clean pseudo-code for operands */
+      switch (code->op)
+      {  case O_NUMBER:
+         case O_STRING:
+         case O_INDEX:
+            break;
+         case O_MEMNUM:
+         case O_MEMSYM:
+            for (e = code->arg.par.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_MEMSET:
+            for (e = code->arg.set.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_MEMVAR:
+            for (e = code->arg.var.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+#if 1 /* 15/V-2010 */
+         case O_MEMCON:
+            for (e = code->arg.con.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+#endif
+         case O_TUPLE:
+         case O_MAKE:
+            for (e = code->arg.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_SLICE:
+            xassert(code != code);
+         case O_IRAND224:
+         case O_UNIFORM01:
+         case O_NORMAL01:
+         case O_GMTIME:
+            break;
+         case O_CVTNUM:
+         case O_CVTSYM:
+         case O_CVTLOG:
+         case O_CVTTUP:
+         case O_CVTLFM:
+         case O_PLUS:
+         case O_MINUS:
+         case O_NOT:
+         case O_ABS:
+         case O_CEIL:
+         case O_FLOOR:
+         case O_EXP:
+         case O_LOG:
+         case O_LOG10:
+         case O_SQRT:
+         case O_SIN:
+         case O_COS:
+         case O_ATAN:
+         case O_ROUND:
+         case O_TRUNC:
+         case O_CARD:
+         case O_LENGTH:
+            /* unary operation */
+            clean_code(mpl, code->arg.arg.x);
+            break;
+         case O_ADD:
+         case O_SUB:
+         case O_LESS:
+         case O_MUL:
+         case O_DIV:
+         case O_IDIV:
+         case O_MOD:
+         case O_POWER:
+         case O_ATAN2:
+         case O_ROUND2:
+         case O_TRUNC2:
+         case O_UNIFORM:
+         case O_NORMAL:
+         case O_CONCAT:
+         case O_LT:
+         case O_LE:
+         case O_EQ:
+         case O_GE:
+         case O_GT:
+         case O_NE:
+         case O_AND:
+         case O_OR:
+         case O_UNION:
+         case O_DIFF:
+         case O_SYMDIFF:
+         case O_INTER:
+         case O_CROSS:
+         case O_IN:
+         case O_NOTIN:
+         case O_WITHIN:
+         case O_NOTWITHIN:
+         case O_SUBSTR:
+         case O_STR2TIME:
+         case O_TIME2STR:
+            /* binary operation */
+            clean_code(mpl, code->arg.arg.x);
+            clean_code(mpl, code->arg.arg.y);
+            break;
+         case O_DOTS:
+         case O_FORK:
+         case O_SUBSTR3:
+            /* ternary operation */
+            clean_code(mpl, code->arg.arg.x);
+            clean_code(mpl, code->arg.arg.y);
+            clean_code(mpl, code->arg.arg.z);
+            break;
+         case O_MIN:
+         case O_MAX:
+            /* n-ary operation */
+            for (e = code->arg.list; e != NULL; e = e->next)
+               clean_code(mpl, e->x);
+            break;
+         case O_SUM:
+         case O_PROD:
+         case O_MINIMUM:
+         case O_MAXIMUM:
+         case O_FORALL:
+         case O_EXISTS:
+         case O_SETOF:
+         case O_BUILD:
+            /* iterated operation */
+            clean_domain(mpl, code->arg.loop.domain);
+            clean_code(mpl, code->arg.loop.x);
+            break;
+         default:
+            xassert(code->op != code->op);
+      }
+done: return;
+}
+
+#if 1 /* 11/II-2008 */
+/**********************************************************************/
+/* * *                        DATA TABLES                         * * */
+/**********************************************************************/
+
+int mpl_tab_num_args(TABDCA *dca)
+{     /* returns the number of arguments */
+      return dca->na;
+}
+
+const char *mpl_tab_get_arg(TABDCA *dca, int k)
+{     /* returns pointer to k-th argument */
+      xassert(1 <= k && k <= dca->na);
+      return dca->arg[k];
+}
+
+int mpl_tab_num_flds(TABDCA *dca)
+{     /* returns the number of fields */
+      return dca->nf;
+}
+
+const char *mpl_tab_get_name(TABDCA *dca, int k)
+{     /* returns pointer to name of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      return dca->name[k];
+}
+
+int mpl_tab_get_type(TABDCA *dca, int k)
+{     /* returns type of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      return dca->type[k];
+}
+
+double mpl_tab_get_num(TABDCA *dca, int k)
+{     /* returns numeric value of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == 'N');
+      return dca->num[k];
+}
+
+const char *mpl_tab_get_str(TABDCA *dca, int k)
+{     /* returns pointer to string value of k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == 'S');
+      xassert(dca->str[k] != NULL);
+      return dca->str[k];
+}
+
+void mpl_tab_set_num(TABDCA *dca, int k, double num)
+{     /* assign numeric value to k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == '?');
+      dca->type[k] = 'N';
+      dca->num[k] = num;
+      return;
+}
+
+void mpl_tab_set_str(TABDCA *dca, int k, const char *str)
+{     /* assign string value to k-th field */
+      xassert(1 <= k && k <= dca->nf);
+      xassert(dca->type[k] == '?');
+      xassert(strlen(str) <= MAX_LENGTH);
+      xassert(dca->str[k] != NULL);
+      dca->type[k] = 'S';
+      strcpy(dca->str[k], str);
+      return;
+}
+
+static int write_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      TABLE *tab = info;
+      TABDCA *dca = mpl->dca;
+      TABOUT *out;
+      SYMBOL *sym;
+      int k;
+      char buf[MAX_LENGTH+1];
+      /* evaluate field values */
+      k = 0;
+      for (out = tab->u.out.list; out != NULL; out = out->next)
+      {  k++;
+         switch (out->code->type)
+         {  case A_NUMERIC:
+               dca->type[k] = 'N';
+               dca->num[k] = eval_numeric(mpl, out->code);
+               dca->str[k][0] = '\0';
+               break;
+            case A_SYMBOLIC:
+               sym = eval_symbolic(mpl, out->code);
+               if (sym->str == NULL)
+               {  dca->type[k] = 'N';
+                  dca->num[k] = sym->num;
+                  dca->str[k][0] = '\0';
+               }
+               else
+               {  dca->type[k] = 'S';
+                  dca->num[k] = 0.0;
+                  fetch_string(mpl, sym->str, buf);
+                  strcpy(dca->str[k], buf);
+               }
+               delete_symbol(mpl, sym);
+               break;
+            default:
+               xassert(out != out);
+         }
+      }
+      /* write record to output table */
+      mpl_tab_drv_write(mpl);
+      return 0;
+}
+
+void execute_table(MPL *mpl, TABLE *tab)
+{     /* execute table statement */
+      TABARG *arg;
+      TABFLD *fld;
+      TABIN *in;
+      TABOUT *out;
+      TABDCA *dca;
+      SET *set;
+      int k;
+      char buf[MAX_LENGTH+1];
+      /* allocate table driver communication area */
+      xassert(mpl->dca == NULL);
+      mpl->dca = dca = xmalloc(sizeof(TABDCA));
+      dca->id = 0;
+      dca->link = NULL;
+      dca->na = 0;
+      dca->arg = NULL;
+      dca->nf = 0;
+      dca->name = NULL;
+      dca->type = NULL;
+      dca->num = NULL;
+      dca->str = NULL;
+      /* allocate arguments */
+      xassert(dca->na == 0);
+      for (arg = tab->arg; arg != NULL; arg = arg->next)
+         dca->na++;
+      dca->arg = xcalloc(1+dca->na, sizeof(char *));
+#if 1 /* 28/IX-2008 */
+      for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL;
+#endif
+      /* evaluate argument values */
+      k = 0;
+      for (arg = tab->arg; arg != NULL; arg = arg->next)
+      {  SYMBOL *sym;
+         k++;
+         xassert(arg->code->type == A_SYMBOLIC);
+         sym = eval_symbolic(mpl, arg->code);
+         if (sym->str == NULL)
+            sprintf(buf, "%.*g", DBL_DIG, sym->num);
+         else
+            fetch_string(mpl, sym->str, buf);
+         delete_symbol(mpl, sym);
+         dca->arg[k] = xmalloc(strlen(buf)+1);
+         strcpy(dca->arg[k], buf);
+      }
+      /* perform table input/output */
+      switch (tab->type)
+      {  case A_INPUT:  goto read_table;
+         case A_OUTPUT: goto write_table;
+         default:       xassert(tab != tab);
+      }
+read_table:
+      /* read data from input table */
+      /* add the only member to the control set and assign it empty
+         elemental set */
+      set = tab->u.in.set;
+      if (set != NULL)
+      {  if (set->data)
+            error(mpl, "%s already provided with data", set->name);
+         xassert(set->array->head == NULL);
+         add_member(mpl, set->array, NULL)->value.set =
+            create_elemset(mpl, set->dimen);
+         set->data = 1;
+      }
+      /* check parameters specified in the input list */
+      for (in = tab->u.in.list; in != NULL; in = in->next)
+      {  if (in->par->data)
+            error(mpl, "%s already provided with data", in->par->name);
+         in->par->data = 1;
+      }
+      /* allocate and initialize fields */
+      xassert(dca->nf == 0);
+      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+         dca->nf++;
+      for (in = tab->u.in.list; in != NULL; in = in->next)
+         dca->nf++;
+      dca->name = xcalloc(1+dca->nf, sizeof(char *));
+      dca->type = xcalloc(1+dca->nf, sizeof(int));
+      dca->num = xcalloc(1+dca->nf, sizeof(double));
+      dca->str = xcalloc(1+dca->nf, sizeof(char *));
+      k = 0;
+      for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+      {  k++;
+         dca->name[k] = fld->name;
+         dca->type[k] = '?';
+         dca->num[k] = 0.0;
+         dca->str[k] = xmalloc(MAX_LENGTH+1);
+         dca->str[k][0] = '\0';
+      }
+      for (in = tab->u.in.list; in != NULL; in = in->next)
+      {  k++;
+         dca->name[k] = in->name;
+         dca->type[k] = '?';
+         dca->num[k] = 0.0;
+         dca->str[k] = xmalloc(MAX_LENGTH+1);
+         dca->str[k][0] = '\0';
+      }
+      /* open input table */
+      mpl_tab_drv_open(mpl, 'R');
+      /* read and process records */
+      for (;;)
+      {  TUPLE *tup;
+         /* reset field types */
+         for (k = 1; k <= dca->nf; k++)
+            dca->type[k] = '?';
+         /* read next record */
+         if (mpl_tab_drv_read(mpl)) break;
+         /* all fields must be set by the driver */
+         for (k = 1; k <= dca->nf; k++)
+         {  if (dca->type[k] == '?')
+               error(mpl, "field %s missing in input table",
+                  dca->name[k]);
+         }
+         /* construct n-tuple */
+         tup = create_tuple(mpl);
+         k = 0;
+         for (fld = tab->u.in.fld; fld != NULL; fld = fld->next)
+         {  k++;
+            xassert(k <= dca->nf);
+            switch (dca->type[k])
+            {  case 'N':
+                  tup = expand_tuple(mpl, tup, create_symbol_num(mpl,
+                     dca->num[k]));
+                  break;
+               case 'S':
+                  xassert(strlen(dca->str[k]) <= MAX_LENGTH);
+                  tup = expand_tuple(mpl, tup, create_symbol_str(mpl,
+                     create_string(mpl, dca->str[k])));
+                  break;
+               default:
+                  xassert(dca != dca);
+            }
+         }
+         /* add n-tuple just read to the control set */
+         if (tab->u.in.set != NULL)
+            check_then_add(mpl, tab->u.in.set->array->head->value.set,
+               copy_tuple(mpl, tup));
+         /* assign values to the parameters in the input list */
+         for (in = tab->u.in.list; in != NULL; in = in->next)
+         {  MEMBER *memb;
+            k++;
+            xassert(k <= dca->nf);
+            /* there must be no member with the same n-tuple */
+            if (find_member(mpl, in->par->array, tup) != NULL)
+               error(mpl, "%s%s already defined", in->par->name,
+               format_tuple(mpl, '[', tup));
+            /* create new parameter member with given n-tuple */
+            memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup))
+               ;
+            /* assign value to the parameter member */
+            switch (in->par->type)
+            {  case A_NUMERIC:
+               case A_INTEGER:
+               case A_BINARY:
+                  if (dca->type[k] != 'N')
+                     error(mpl, "%s requires numeric data",
+                        in->par->name);
+                  memb->value.num = dca->num[k];
+                  break;
+               case A_SYMBOLIC:
+                  switch (dca->type[k])
+                  {  case 'N':
+                        memb->value.sym = create_symbol_num(mpl,
+                           dca->num[k]);
+                        break;
+                     case 'S':
+                        xassert(strlen(dca->str[k]) <= MAX_LENGTH);
+                        memb->value.sym = create_symbol_str(mpl,
+                           create_string(mpl,dca->str[k]));
+                        break;
+                     default:
+                        xassert(dca != dca);
+                  }
+                  break;
+               default:
+                  xassert(in != in);
+            }
+         }
+         /* n-tuple is no more needed */
+         delete_tuple(mpl, tup);
+      }
+      /* close input table */
+      mpl_tab_drv_close(mpl);
+      goto done;
+write_table:
+      /* write data to output table */
+      /* allocate and initialize fields */
+      xassert(dca->nf == 0);
+      for (out = tab->u.out.list; out != NULL; out = out->next)
+         dca->nf++;
+      dca->name = xcalloc(1+dca->nf, sizeof(char *));
+      dca->type = xcalloc(1+dca->nf, sizeof(int));
+      dca->num = xcalloc(1+dca->nf, sizeof(double));
+      dca->str = xcalloc(1+dca->nf, sizeof(char *));
+      k = 0;
+      for (out = tab->u.out.list; out != NULL; out = out->next)
+      {  k++;
+         dca->name[k] = out->name;
+         dca->type[k] = '?';
+         dca->num[k] = 0.0;
+         dca->str[k] = xmalloc(MAX_LENGTH+1);
+         dca->str[k][0] = '\0';
+      }
+      /* open output table */
+      mpl_tab_drv_open(mpl, 'W');
+      /* evaluate fields and write records */
+      loop_within_domain(mpl, tab->u.out.domain, tab, write_func);
+      /* close output table */
+      mpl_tab_drv_close(mpl);
+done: /* free table driver communication area */
+      free_dca(mpl);
+      return;
+}
+
+void free_dca(MPL *mpl)
+{     /* free table driver communucation area */
+      TABDCA *dca = mpl->dca;
+      int k;
+      if (dca != NULL)
+      {  if (dca->link != NULL)
+            mpl_tab_drv_close(mpl);
+         if (dca->arg != NULL)
+         {  for (k = 1; k <= dca->na; k++)
+#if 1 /* 28/IX-2008 */
+               if (dca->arg[k] != NULL)
+#endif
+               xfree(dca->arg[k]);
+            xfree(dca->arg);
+         }
+         if (dca->name != NULL) xfree(dca->name);
+         if (dca->type != NULL) xfree(dca->type);
+         if (dca->num != NULL) xfree(dca->num);
+         if (dca->str != NULL)
+         {  for (k = 1; k <= dca->nf; k++)
+               xfree(dca->str[k]);
+            xfree(dca->str);
+         }
+         xfree(dca), mpl->dca = NULL;
+      }
+      return;
+}
+
+void clean_table(MPL *mpl, TABLE *tab)
+{     /* clean table statement */
+      TABARG *arg;
+      TABOUT *out;
+      /* clean string list */
+      for (arg = tab->arg; arg != NULL; arg = arg->next)
+         clean_code(mpl, arg->code);
+      switch (tab->type)
+      {  case A_INPUT:
+            break;
+         case A_OUTPUT:
+            /* clean subscript domain */
+            clean_domain(mpl, tab->u.out.domain);
+            /* clean output list */
+            for (out = tab->u.out.list; out != NULL; out = out->next)
+               clean_code(mpl, out->code);
+            break;
+         default:
+            xassert(tab != tab);
+      }
+      return;
+}
+#endif
+
+/**********************************************************************/
+/* * *                      MODEL STATEMENTS                      * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- execute_check - execute check statement.
+--
+-- This routine executes specified check statement. */
+
+static int check_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      CHECK *chk = (CHECK *)info;
+      if (!eval_logical(mpl, chk->code))
+         error(mpl, "check%s failed", format_tuple(mpl, '[',
+            get_domain_tuple(mpl, chk->domain)));
+      return 0;
+}
+
+void execute_check(MPL *mpl, CHECK *chk)
+{     loop_within_domain(mpl, chk->domain, chk, check_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_check - clean check statement.
+--
+-- This routine cleans specified check statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_check(MPL *mpl, CHECK *chk)
+{     /* clean subscript domain */
+      clean_domain(mpl, chk->domain);
+      /* clean pseudo-code for computing predicate */
+      clean_code(mpl, chk->code);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_display - execute display statement.
+--
+-- This routine executes specified display statement. */
+
+static void display_set(MPL *mpl, SET *set, MEMBER *memb)
+{     /* display member of model set */
+      ELEMSET *s = memb->value.set;
+      MEMBER *m;
+      write_text(mpl, "%s%s%s\n", set->name,
+         format_tuple(mpl, '[', memb->tuple),
+         s->head == NULL ? " is empty" : ":");
+      for (m = s->head; m != NULL; m = m->next)
+         write_text(mpl, "   %s\n", format_tuple(mpl, '(', m->tuple));
+      return;
+}
+
+static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb)
+{     /* display member of model parameter */
+      switch (par->type)
+      {  case A_NUMERIC:
+         case A_INTEGER:
+         case A_BINARY:
+            write_text(mpl, "%s%s = %.*g\n", par->name,
+               format_tuple(mpl, '[', memb->tuple),
+               DBL_DIG, memb->value.num);
+            break;
+         case A_SYMBOLIC:
+            write_text(mpl, "%s%s = %s\n", par->name,
+               format_tuple(mpl, '[', memb->tuple),
+               format_symbol(mpl, memb->value.sym));
+            break;
+         default:
+            xassert(par != par);
+      }
+      return;
+}
+
+#if 1 /* 15/V-2010 */
+static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb,
+      int suff)
+{     /* display member of model variable */
+      if (suff == DOT_NONE || suff == DOT_VAL)
+         write_text(mpl, "%s%s.val = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->prim);
+      else if (suff == DOT_LB)
+         write_text(mpl, "%s%s.lb = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->var->lbnd == NULL ? -DBL_MAX :
+            memb->value.var->lbnd);
+      else if (suff == DOT_UB)
+         write_text(mpl, "%s%s.ub = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->var->ubnd == NULL ? +DBL_MAX :
+            memb->value.var->ubnd);
+      else if (suff == DOT_STATUS)
+         write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple
+            (mpl, '[', memb->tuple), memb->value.var->stat);
+      else if (suff == DOT_DUAL)
+         write_text(mpl, "%s%s.dual = %.*g\n", var->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.var->dual);
+      else
+         xassert(suff != suff);
+      return;
+}
+#endif
+
+#if 1 /* 15/V-2010 */
+static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb,
+      int suff)
+{     /* display member of model constraint */
+      if (suff == DOT_NONE || suff == DOT_VAL)
+         write_text(mpl, "%s%s.val = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->prim);
+      else if (suff == DOT_LB)
+         write_text(mpl, "%s%s.lb = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->con->lbnd == NULL ? -DBL_MAX :
+            memb->value.con->lbnd);
+      else if (suff == DOT_UB)
+         write_text(mpl, "%s%s.ub = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->con->ubnd == NULL ? +DBL_MAX :
+            memb->value.con->ubnd);
+      else if (suff == DOT_STATUS)
+         write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple
+            (mpl, '[', memb->tuple), memb->value.con->stat);
+      else if (suff == DOT_DUAL)
+         write_text(mpl, "%s%s.dual = %.*g\n", con->name,
+            format_tuple(mpl, '[', memb->tuple), DBL_DIG,
+            memb->value.con->dual);
+      else
+         xassert(suff != suff);
+      return;
+}
+#endif
+
+static void display_memb(MPL *mpl, CODE *code)
+{     /* display member specified by pseudo-code */
+      MEMBER memb;
+      ARG_LIST *e;
+      xassert(code->op == O_MEMNUM || code->op == O_MEMSYM
+         || code->op == O_MEMSET || code->op == O_MEMVAR
+         || code->op == O_MEMCON);
+      memb.tuple = create_tuple(mpl);
+      for (e = code->arg.par.list; e != NULL; e = e->next)
+         memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl,
+            e->x));
+      switch (code->op)
+      {  case O_MEMNUM:
+            memb.value.num = eval_member_num(mpl, code->arg.par.par,
+               memb.tuple);
+            display_par(mpl, code->arg.par.par, &memb);
+            break;
+         case O_MEMSYM:
+            memb.value.sym = eval_member_sym(mpl, code->arg.par.par,
+               memb.tuple);
+            display_par(mpl, code->arg.par.par, &memb);
+            delete_symbol(mpl, memb.value.sym);
+            break;
+         case O_MEMSET:
+            memb.value.set = eval_member_set(mpl, code->arg.set.set,
+               memb.tuple);
+            display_set(mpl, code->arg.set.set, &memb);
+            break;
+         case O_MEMVAR:
+            memb.value.var = eval_member_var(mpl, code->arg.var.var,
+               memb.tuple);
+            display_var
+               (mpl, code->arg.var.var, &memb, code->arg.var.suff);
+            break;
+         case O_MEMCON:
+            memb.value.con = eval_member_con(mpl, code->arg.con.con,
+               memb.tuple);
+            display_con
+               (mpl, code->arg.con.con, &memb, code->arg.con.suff);
+            break;
+         default:
+            xassert(code != code);
+      }
+      delete_tuple(mpl, memb.tuple);
+      return;
+}
+
+static void display_code(MPL *mpl, CODE *code)
+{     /* display value of expression */
+      switch (code->type)
+      {  case A_NUMERIC:
+            /* numeric value */
+            {  double num;
+               num = eval_numeric(mpl, code);
+               write_text(mpl, "%.*g\n", DBL_DIG, num);
+            }
+            break;
+         case A_SYMBOLIC:
+            /* symbolic value */
+            {  SYMBOL *sym;
+               sym = eval_symbolic(mpl, code);
+               write_text(mpl, "%s\n", format_symbol(mpl, sym));
+               delete_symbol(mpl, sym);
+            }
+            break;
+         case A_LOGICAL:
+            /* logical value */
+            {  int bit;
+               bit = eval_logical(mpl, code);
+               write_text(mpl, "%s\n", bit ? "true" : "false");
+            }
+            break;
+         case A_TUPLE:
+            /* n-tuple */
+            {  TUPLE *tuple;
+               tuple = eval_tuple(mpl, code);
+               write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple));
+               delete_tuple(mpl, tuple);
+            }
+            break;
+         case A_ELEMSET:
+            /* elemental set */
+            {  ELEMSET *set;
+               MEMBER *memb;
+               set = eval_elemset(mpl, code);
+               if (set->head == 0)
+                  write_text(mpl, "set is empty\n");
+               for (memb = set->head; memb != NULL; memb = memb->next)
+                  write_text(mpl, "   %s\n", format_tuple(mpl, '(',
+                     memb->tuple));
+               delete_elemset(mpl, set);
+            }
+            break;
+         case A_FORMULA:
+            /* linear form */
+            {  FORMULA *form, *term;
+               form = eval_formula(mpl, code);
+               if (form == NULL)
+                  write_text(mpl, "linear form is empty\n");
+               for (term = form; term != NULL; term = term->next)
+               {  if (term->var == NULL)
+                     write_text(mpl, "   %.*g\n", term->coef);
+                  else
+                     write_text(mpl, "   %.*g %s%s\n", DBL_DIG,
+                        term->coef, term->var->var->name,
+                        format_tuple(mpl, '[', term->var->memb->tuple));
+               }
+               delete_formula(mpl, form);
+            }
+            break;
+         default:
+            xassert(code != code);
+      }
+      return;
+}
+
+static int display_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      DISPLAY *dpy = (DISPLAY *)info;
+      DISPLAY1 *entry;
+      for (entry = dpy->list; entry != NULL; entry = entry->next)
+      {  if (entry->type == A_INDEX)
+         {  /* dummy index */
+            DOMAIN_SLOT *slot = entry->u.slot;
+            write_text(mpl, "%s = %s\n", slot->name,
+            format_symbol(mpl, slot->value));
+         }
+         else if (entry->type == A_SET)
+         {  /* model set */
+            SET *set = entry->u.set;
+            MEMBER *memb;
+            if (set->assign != NULL)
+            {  /* the set has assignment expression; evaluate all its
+                  members over entire domain */
+               eval_whole_set(mpl, set);
+            }
+            else
+            {  /* the set has no assignment expression; refer to its
+                  any existing member ignoring resultant value to check
+                  the data provided the data section */
+#if 1 /* 12/XII-2008 */
+               if (set->gadget != NULL && set->data == 0)
+               {  /* initialize the set with data from a plain set */
+                  saturate_set(mpl, set);
+               }
+#endif
+               if (set->array->head != NULL)
+                  eval_member_set(mpl, set, set->array->head->tuple);
+            }
+            /* display all members of the set array */
+            if (set->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", set->name);
+            for (memb = set->array->head; memb != NULL; memb =
+               memb->next) display_set(mpl, set, memb);
+         }
+         else if (entry->type == A_PARAMETER)
+         {  /* model parameter */
+            PARAMETER *par = entry->u.par;
+            MEMBER *memb;
+            if (par->assign != NULL)
+            {  /* the parameter has an assignment expression; evaluate
+                  all its member over entire domain */
+               eval_whole_par(mpl, par);
+            }
+            else
+            {  /* the parameter has no assignment expression; refer to
+                  its any existing member ignoring resultant value to
+                  check the data provided in the data section */
+               if (par->array->head != NULL)
+               {  if (par->type != A_SYMBOLIC)
+                     eval_member_num(mpl, par, par->array->head->tuple);
+                  else
+                     delete_symbol(mpl, eval_member_sym(mpl, par,
+                        par->array->head->tuple));
+               }
+            }
+            /* display all members of the parameter array */
+            if (par->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", par->name);
+            for (memb = par->array->head; memb != NULL; memb =
+               memb->next) display_par(mpl, par, memb);
+         }
+         else if (entry->type == A_VARIABLE)
+         {  /* model variable */
+            VARIABLE *var = entry->u.var;
+            MEMBER *memb;
+            xassert(mpl->flag_p);
+            /* display all members of the variable array */
+            if (var->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", var->name);
+            for (memb = var->array->head; memb != NULL; memb =
+               memb->next) display_var(mpl, var, memb, DOT_NONE);
+         }
+         else if (entry->type == A_CONSTRAINT)
+         {  /* model constraint */
+            CONSTRAINT *con = entry->u.con;
+            MEMBER *memb;
+            xassert(mpl->flag_p);
+            /* display all members of the constraint array */
+            if (con->array->head == NULL)
+               write_text(mpl, "%s has empty content\n", con->name);
+            for (memb = con->array->head; memb != NULL; memb =
+               memb->next) display_con(mpl, con, memb, DOT_NONE);
+         }
+         else if (entry->type == A_EXPRESSION)
+         {  /* expression */
+            CODE *code = entry->u.code;
+            if (code->op == O_MEMNUM || code->op == O_MEMSYM ||
+                code->op == O_MEMSET || code->op == O_MEMVAR ||
+                code->op == O_MEMCON)
+               display_memb(mpl, code);
+            else
+               display_code(mpl, code);
+         }
+         else
+            xassert(entry != entry);
+      }
+      return 0;
+}
+
+void execute_display(MPL *mpl, DISPLAY *dpy)
+{     loop_within_domain(mpl, dpy->domain, dpy, display_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_display - clean display statement.
+--
+-- This routine cleans specified display statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_display(MPL *mpl, DISPLAY *dpy)
+{     DISPLAY1 *d;
+#if 0 /* 15/V-2010 */
+      ARG_LIST *e;
+#endif
+      /* clean subscript domain */
+      clean_domain(mpl, dpy->domain);
+      /* clean display list */
+      for (d = dpy->list; d != NULL; d = d->next)
+      {  /* clean pseudo-code for computing expression */
+         if (d->type == A_EXPRESSION)
+            clean_code(mpl, d->u.code);
+#if 0 /* 15/V-2010 */
+         /* clean pseudo-code for computing subscripts */
+         for (e = d->list; e != NULL; e = e->next)
+            clean_code(mpl, e->x);
+#endif
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_printf - execute printf statement.
+--
+-- This routine executes specified printf statement. */
+
+#if 1 /* 14/VII-2006 */
+static void print_char(MPL *mpl, int c)
+{     if (mpl->prt_fp == NULL)
+         write_char(mpl, c);
+      else
+         xfputc(c, mpl->prt_fp);
+      return;
+}
+
+static void print_text(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char buf[OUTBUF_SIZE], *c;
+      va_start(arg, fmt);
+      vsprintf(buf, fmt, arg);
+      xassert(strlen(buf) < sizeof(buf));
+      va_end(arg);
+      for (c = buf; *c != '\0'; c++) print_char(mpl, *c);
+      return;
+}
+#endif
+
+static int printf_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      PRINTF *prt = (PRINTF *)info;
+      PRINTF1 *entry;
+      SYMBOL *sym;
+      char fmt[MAX_LENGTH+1], *c, *from, save;
+      /* evaluate format control string */
+      sym = eval_symbolic(mpl, prt->fmt);
+      if (sym->str == NULL)
+         sprintf(fmt, "%.*g", DBL_DIG, sym->num);
+      else
+         fetch_string(mpl, sym->str, fmt);
+      delete_symbol(mpl, sym);
+      /* scan format control string and perform formatting output */
+      entry = prt->list;
+      for (c = fmt; *c != '\0'; c++)
+      {  if (*c == '%')
+         {  /* scan format specifier */
+            from = c++;
+            if (*c == '%')
+            {  print_char(mpl, '%');
+               continue;
+            }
+            if (entry == NULL) break;
+            /* scan optional flags */
+            while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' ||
+                   *c == '0') c++;
+            /* scan optional minimum field width */
+            while (isdigit((unsigned char)*c)) c++;
+            /* scan optional precision */
+            if (*c == '.')
+            {  c++;
+               while (isdigit((unsigned char)*c)) c++;
+            }
+            /* scan conversion specifier and perform formatting */
+            save = *(c+1), *(c+1) = '\0';
+            if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' ||
+                *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G')
+            {  /* the specifier requires numeric value */
+               double value;
+               xassert(entry != NULL);
+               switch (entry->code->type)
+               {  case A_NUMERIC:
+                     value = eval_numeric(mpl, entry->code);
+                     break;
+                  case A_SYMBOLIC:
+                     sym = eval_symbolic(mpl, entry->code);
+                     if (sym->str != NULL)
+                        error(mpl, "cannot convert %s to floating-point"
+                           " number", format_symbol(mpl, sym));
+                     value = sym->num;
+                     delete_symbol(mpl, sym);
+                     break;
+                  case A_LOGICAL:
+                     if (eval_logical(mpl, entry->code))
+                        value = 1.0;
+                     else
+                        value = 0.0;
+                     break;
+                  default:
+                     xassert(entry != entry);
+               }
+               if (*c == 'd' || *c == 'i')
+               {  double int_max = (double)INT_MAX;
+                  if (!(-int_max <= value && value <= +int_max))
+                     error(mpl, "cannot convert %.*g to integer",
+                        DBL_DIG, value);
+                  print_text(mpl, from, (int)floor(value + 0.5));
+               }
+               else
+                  print_text(mpl, from, value);
+            }
+            else if (*c == 's')
+            {  /* the specifier requires symbolic value */
+               char value[MAX_LENGTH+1];
+               switch (entry->code->type)
+               {  case A_NUMERIC:
+                     sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl,
+                        entry->code));
+                     break;
+                  case A_LOGICAL:
+                     if (eval_logical(mpl, entry->code))
+                        strcpy(value, "T");
+                     else
+                        strcpy(value, "F");
+                     break;
+                  case A_SYMBOLIC:
+                     sym = eval_symbolic(mpl, entry->code);
+                     if (sym->str == NULL)
+                        sprintf(value, "%.*g", DBL_DIG, sym->num);
+                     else
+                        fetch_string(mpl, sym->str, value);
+                     delete_symbol(mpl, sym);
+                     break;
+                  default:
+                     xassert(entry != entry);
+               }
+               print_text(mpl, from, value);
+            }
+            else
+               error(mpl, "format specifier missing or invalid");
+            *(c+1) = save;
+            entry = entry->next;
+         }
+         else if (*c == '\\')
+         {  /* write some control character */
+            c++;
+            if (*c == 't')
+               print_char(mpl, '\t');
+            else if (*c == 'n')
+               print_char(mpl, '\n');
+#if 1 /* 28/X-2010 */
+            else if (*c == '\0')
+            {  /* format string ends with backslash */
+               error(mpl, "invalid use of escape character \\ in format"
+                  " control string");
+            }
+#endif
+            else
+               print_char(mpl, *c);
+         }
+         else
+         {  /* write character without formatting */
+            print_char(mpl, *c);
+         }
+      }
+      return 0;
+}
+
+#if 0 /* 14/VII-2006 */
+void execute_printf(MPL *mpl, PRINTF *prt)
+{     loop_within_domain(mpl, prt->domain, prt, printf_func);
+      return;
+}
+#else
+void execute_printf(MPL *mpl, PRINTF *prt)
+{     if (prt->fname == NULL)
+      {  /* switch to the standard output */
+         if (mpl->prt_fp != NULL)
+         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
+            xfree(mpl->prt_file), mpl->prt_file = NULL;
+         }
+      }
+      else
+      {  /* evaluate file name string */
+         SYMBOL *sym;
+         char fname[MAX_LENGTH+1];
+         sym = eval_symbolic(mpl, prt->fname);
+         if (sym->str == NULL)
+            sprintf(fname, "%.*g", DBL_DIG, sym->num);
+         else
+            fetch_string(mpl, sym->str, fname);
+         delete_symbol(mpl, sym);
+         /* close the current print file, if necessary */
+         if (mpl->prt_fp != NULL &&
+            (!prt->app || strcmp(mpl->prt_file, fname) != 0))
+         {  xfclose(mpl->prt_fp), mpl->prt_fp = NULL;
+            xfree(mpl->prt_file), mpl->prt_file = NULL;
+         }
+         /* open the specified print file, if necessary */
+         if (mpl->prt_fp == NULL)
+         {  mpl->prt_fp = xfopen(fname, prt->app ? "a" : "w");
+            if (mpl->prt_fp == NULL)
+               error(mpl, "unable to open `%s' for writing - %s",
+                  fname, xerrmsg());
+            mpl->prt_file = xmalloc(strlen(fname)+1);
+            strcpy(mpl->prt_file, fname);
+         }
+      }
+      loop_within_domain(mpl, prt->domain, prt, printf_func);
+      if (mpl->prt_fp != NULL)
+      {  xfflush(mpl->prt_fp);
+         if (xferror(mpl->prt_fp))
+            error(mpl, "writing error to `%s' - %s", mpl->prt_file,
+               xerrmsg());
+      }
+      return;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- clean_printf - clean printf statement.
+--
+-- This routine cleans specified printf statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_printf(MPL *mpl, PRINTF *prt)
+{     PRINTF1 *p;
+      /* clean subscript domain */
+      clean_domain(mpl, prt->domain);
+      /* clean pseudo-code for computing format string */
+      clean_code(mpl, prt->fmt);
+      /* clean printf list */
+      for (p = prt->list; p != NULL; p = p->next)
+      {  /* clean pseudo-code for computing value to be printed */
+         clean_code(mpl, p->code);
+      }
+#if 1 /* 14/VII-2006 */
+      /* clean pseudo-code for computing file name string */
+      clean_code(mpl, prt->fname);
+#endif
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_for - execute for statement.
+--
+-- This routine executes specified for statement. */
+
+static int for_func(MPL *mpl, void *info)
+{     /* this is auxiliary routine to work within domain scope */
+      FOR *fur = (FOR *)info;
+      STATEMENT *stmt, *save;
+      save = mpl->stmt;
+      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
+         execute_statement(mpl, stmt);
+      mpl->stmt = save;
+      return 0;
+}
+
+void execute_for(MPL *mpl, FOR *fur)
+{     loop_within_domain(mpl, fur->domain, fur, for_func);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_for - clean for statement.
+--
+-- This routine cleans specified for statement that assumes deleting all
+-- stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_for(MPL *mpl, FOR *fur)
+{     STATEMENT *stmt;
+      /* clean subscript domain */
+      clean_domain(mpl, fur->domain);
+      /* clean all sub-statements */
+      for (stmt = fur->list; stmt != NULL; stmt = stmt->next)
+         clean_statement(mpl, stmt);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- execute_statement - execute specified model statement.
+--
+-- This routine executes specified model statement. */
+
+void execute_statement(MPL *mpl, STATEMENT *stmt)
+{     mpl->stmt = stmt;
+      switch (stmt->type)
+      {  case A_SET:
+         case A_PARAMETER:
+         case A_VARIABLE:
+            break;
+         case A_CONSTRAINT:
+            xprintf("Generating %s...\n", stmt->u.con->name);
+            eval_whole_con(mpl, stmt->u.con);
+            break;
+         case A_TABLE:
+            switch (stmt->u.tab->type)
+            {  case A_INPUT:
+                  xprintf("Reading %s...\n", stmt->u.tab->name);
+                  break;
+               case A_OUTPUT:
+                  xprintf("Writing %s...\n", stmt->u.tab->name);
+                  break;
+               default:
+                  xassert(stmt != stmt);
+            }
+            execute_table(mpl, stmt->u.tab);
+            break;
+         case A_SOLVE:
+            break;
+         case A_CHECK:
+            xprintf("Checking (line %d)...\n", stmt->line);
+            execute_check(mpl, stmt->u.chk);
+            break;
+         case A_DISPLAY:
+            write_text(mpl, "Display statement at line %d\n",
+               stmt->line);
+            execute_display(mpl, stmt->u.dpy);
+            break;
+         case A_PRINTF:
+            execute_printf(mpl, stmt->u.prt);
+            break;
+         case A_FOR:
+            execute_for(mpl, stmt->u.fur);
+            break;
+         default:
+            xassert(stmt != stmt);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_statement - clean specified model statement.
+--
+-- This routine cleans specified model statement that assumes deleting
+-- all stuff dynamically allocated on generating/postsolving phase. */
+
+void clean_statement(MPL *mpl, STATEMENT *stmt)
+{     switch(stmt->type)
+      {  case A_SET:
+            clean_set(mpl, stmt->u.set); break;
+         case A_PARAMETER:
+            clean_parameter(mpl, stmt->u.par); break;
+         case A_VARIABLE:
+            clean_variable(mpl, stmt->u.var); break;
+         case A_CONSTRAINT:
+            clean_constraint(mpl, stmt->u.con); break;
+#if 1 /* 11/II-2008 */
+         case A_TABLE:
+            clean_table(mpl, stmt->u.tab); break;
+#endif
+         case A_SOLVE:
+            break;
+         case A_CHECK:
+            clean_check(mpl, stmt->u.chk); break;
+         case A_DISPLAY:
+            clean_display(mpl, stmt->u.dpy); break;
+         case A_PRINTF:
+            clean_printf(mpl, stmt->u.prt); break;
+         case A_FOR:
+            clean_for(mpl, stmt->u.fur); break;
+         default:
+            xassert(stmt != stmt);
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpmpl04.c
===================================================================
--- deps/glpk/src/glpmpl04.c	(revision 9)
+++ deps/glpk/src/glpmpl04.c	(revision 9)
@@ -0,0 +1,1424 @@
+/* glpmpl04.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpmpl.h"
+#define xfault xerror
+#define dmp_create_poolx(size) dmp_create_pool()
+
+/**********************************************************************/
+/* * *              GENERATING AND POSTSOLVING MODEL              * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- alloc_content - allocate content arrays for all model objects.
+--
+-- This routine allocates content arrays for all existing model objects
+-- and thereby finalizes creating model.
+--
+-- This routine must be called immediately after reading model section,
+-- i.e. before reading data section or generating model. */
+
+void alloc_content(MPL *mpl)
+{     STATEMENT *stmt;
+      /* walk through all model statements */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  switch (stmt->type)
+         {  case A_SET:
+               /* model set */
+               xassert(stmt->u.set->array == NULL);
+               stmt->u.set->array = create_array(mpl, A_ELEMSET,
+                  stmt->u.set->dim);
+               break;
+            case A_PARAMETER:
+               /* model parameter */
+               xassert(stmt->u.par->array == NULL);
+               switch (stmt->u.par->type)
+               {  case A_NUMERIC:
+                  case A_INTEGER:
+                  case A_BINARY:
+                     stmt->u.par->array = create_array(mpl, A_NUMERIC,
+                        stmt->u.par->dim);
+                     break;
+                  case A_SYMBOLIC:
+                     stmt->u.par->array = create_array(mpl, A_SYMBOLIC,
+                        stmt->u.par->dim);
+                     break;
+                  default:
+                     xassert(stmt != stmt);
+               }
+               break;
+            case A_VARIABLE:
+               /* model variable */
+               xassert(stmt->u.var->array == NULL);
+               stmt->u.var->array = create_array(mpl, A_ELEMVAR,
+                  stmt->u.var->dim);
+               break;
+            case A_CONSTRAINT:
+               /* model constraint/objective */
+               xassert(stmt->u.con->array == NULL);
+               stmt->u.con->array = create_array(mpl, A_ELEMCON,
+                  stmt->u.con->dim);
+               break;
+#if 1 /* 11/II-2008 */
+            case A_TABLE:
+#endif
+            case A_SOLVE:
+            case A_CHECK:
+            case A_DISPLAY:
+            case A_PRINTF:
+            case A_FOR:
+               /* functional statements have no content array */
+               break;
+            default:
+               xassert(stmt != stmt);
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- generate_model - generate model.
+--
+-- This routine executes the model statements which precede the solve
+-- statement. */
+
+void generate_model(MPL *mpl)
+{     STATEMENT *stmt;
+      xassert(!mpl->flag_p);
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  execute_statement(mpl, stmt);
+         if (mpl->stmt->type == A_SOLVE) break;
+      }
+      mpl->stmt = stmt;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- build_problem - build problem instance.
+--
+-- This routine builds lists of rows and columns for problem instance,
+-- which corresponds to the generated model. */
+
+void build_problem(MPL *mpl)
+{     STATEMENT *stmt;
+      MEMBER *memb;
+      VARIABLE *v;
+      CONSTRAINT *c;
+      FORMULA *t;
+      int i, j;
+      xassert(mpl->m == 0);
+      xassert(mpl->n == 0);
+      xassert(mpl->row == NULL);
+      xassert(mpl->col == NULL);
+      /* check that all elemental variables has zero column numbers */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_VARIABLE)
+         {  v = stmt->u.var;
+            for (memb = v->array->head; memb != NULL; memb = memb->next)
+               xassert(memb->value.var->j == 0);
+         }
+      }
+      /* assign row numbers to elemental constraints and objectives */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_CONSTRAINT)
+         {  c = stmt->u.con;
+            for (memb = c->array->head; memb != NULL; memb = memb->next)
+            {  xassert(memb->value.con->i == 0);
+               memb->value.con->i = ++mpl->m;
+               /* walk through linear form and mark elemental variables,
+                  which are referenced at least once */
+               for (t = memb->value.con->form; t != NULL; t = t->next)
+               {  xassert(t->var != NULL);
+                  t->var->memb->value.var->j = -1;
+               }
+            }
+         }
+      }
+      /* assign column numbers to marked elemental variables */
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_VARIABLE)
+         {  v = stmt->u.var;
+            for (memb = v->array->head; memb != NULL; memb = memb->next)
+               if (memb->value.var->j != 0) memb->value.var->j =
+                  ++mpl->n;
+         }
+      }
+      /* build list of rows */
+      mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *));
+      for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL;
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_CONSTRAINT)
+         {  c = stmt->u.con;
+            for (memb = c->array->head; memb != NULL; memb = memb->next)
+            {  i = memb->value.con->i;
+               xassert(1 <= i && i <= mpl->m);
+               xassert(mpl->row[i] == NULL);
+               mpl->row[i] = memb->value.con;
+            }
+         }
+      }
+      for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL);
+      /* build list of columns */
+      mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *));
+      for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL;
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+      {  if (stmt->type == A_VARIABLE)
+         {  v = stmt->u.var;
+            for (memb = v->array->head; memb != NULL; memb = memb->next)
+            {  j = memb->value.var->j;
+               if (j == 0) continue;
+               xassert(1 <= j && j <= mpl->n);
+               xassert(mpl->col[j] == NULL);
+               mpl->col[j] = memb->value.var;
+            }
+         }
+      }
+      for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- postsolve_model - postsolve model.
+--
+-- This routine executes the model statements which follow the solve
+-- statement. */
+
+void postsolve_model(MPL *mpl)
+{     STATEMENT *stmt;
+      xassert(!mpl->flag_p);
+      mpl->flag_p = 1;
+      for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next)
+         execute_statement(mpl, stmt);
+      mpl->stmt = NULL;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- clean_model - clean model content.
+--
+-- This routine cleans the model content that assumes deleting all stuff
+-- dynamically allocated on generating/postsolving phase.
+--
+-- Actually cleaning model content is not needed. This function is used
+-- mainly to be sure that there were no logical errors on using dynamic
+-- memory pools during the generation phase.
+--
+-- NOTE: This routine must not be called if any errors were detected on
+--       the generation phase. */
+
+void clean_model(MPL *mpl)
+{     STATEMENT *stmt;
+      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
+         clean_statement(mpl, stmt);
+      /* check that all atoms have been returned to their pools */
+      if (dmp_in_use(mpl->strings).lo != 0)
+         error(mpl, "internal logic error: %d string segment(s) were lo"
+            "st", dmp_in_use(mpl->strings).lo);
+      if (dmp_in_use(mpl->symbols).lo != 0)
+         error(mpl, "internal logic error: %d symbol(s) were lost",
+            dmp_in_use(mpl->symbols).lo);
+      if (dmp_in_use(mpl->tuples).lo != 0)
+         error(mpl, "internal logic error: %d n-tuple component(s) were"
+            " lost", dmp_in_use(mpl->tuples).lo);
+      if (dmp_in_use(mpl->arrays).lo != 0)
+         error(mpl, "internal logic error: %d array(s) were lost",
+            dmp_in_use(mpl->arrays).lo);
+      if (dmp_in_use(mpl->members).lo != 0)
+         error(mpl, "internal logic error: %d array member(s) were lost"
+            , dmp_in_use(mpl->members).lo);
+      if (dmp_in_use(mpl->elemvars).lo != 0)
+         error(mpl, "internal logic error: %d elemental variable(s) wer"
+            "e lost", dmp_in_use(mpl->elemvars).lo);
+      if (dmp_in_use(mpl->formulae).lo != 0)
+         error(mpl, "internal logic error: %d linear term(s) were lost",
+            dmp_in_use(mpl->formulae).lo);
+      if (dmp_in_use(mpl->elemcons).lo != 0)
+         error(mpl, "internal logic error: %d elemental constraint(s) w"
+            "ere lost", dmp_in_use(mpl->elemcons).lo);
+      return;
+}
+
+/**********************************************************************/
+/* * *                        INPUT/OUTPUT                        * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- open_input - open input text file.
+--
+-- This routine opens the input text file for scanning. */
+
+void open_input(MPL *mpl, char *file)
+{     mpl->line = 0;
+      mpl->c = '\n';
+      mpl->token = 0;
+      mpl->imlen = 0;
+      mpl->image[0] = '\0';
+      mpl->value = 0.0;
+      mpl->b_token = T_EOF;
+      mpl->b_imlen = 0;
+      mpl->b_image[0] = '\0';
+      mpl->b_value = 0.0;
+      mpl->f_dots = 0;
+      mpl->f_scan = 0;
+      mpl->f_token = 0;
+      mpl->f_imlen = 0;
+      mpl->f_image[0] = '\0';
+      mpl->f_value = 0.0;
+      memset(mpl->context, ' ', CONTEXT_SIZE);
+      mpl->c_ptr = 0;
+      xassert(mpl->in_fp == NULL);
+      mpl->in_fp = xfopen(file, "r");
+      if (mpl->in_fp == NULL)
+         error(mpl, "unable to open %s - %s", file, xerrmsg());
+      mpl->in_file = file;
+      /* scan the very first character */
+      get_char(mpl);
+      /* scan the very first token */
+      get_token(mpl);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- read_char - read next character from input text file.
+--
+-- This routine returns a next ASCII character read from the input text
+-- file. If the end of file has been reached, EOF is returned. */
+
+int read_char(MPL *mpl)
+{     int c;
+      xassert(mpl->in_fp != NULL);
+      c = xfgetc(mpl->in_fp);
+      if (c < 0)
+      {  if (xferror(mpl->in_fp))
+            error(mpl, "read error on %s - %s", mpl->in_file,
+               xerrmsg());
+         c = EOF;
+      }
+      return c;
+}
+
+/*----------------------------------------------------------------------
+-- close_input - close input text file.
+--
+-- This routine closes the input text file. */
+
+void close_input(MPL *mpl)
+{     xassert(mpl->in_fp != NULL);
+      xfclose(mpl->in_fp);
+      mpl->in_fp = NULL;
+      mpl->in_file = NULL;
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- open_output - open output text file.
+--
+-- This routine opens the output text file for writing data produced by
+-- display and printf statements. */
+
+void open_output(MPL *mpl, char *file)
+{     xassert(mpl->out_fp == NULL);
+      if (file == NULL)
+      {  file = "<stdout>";
+         mpl->out_fp = (void *)stdout;
+      }
+      else
+      {  mpl->out_fp = xfopen(file, "w");
+         if (mpl->out_fp == NULL)
+            error(mpl, "unable to create %s - %s", file, xerrmsg());
+      }
+      mpl->out_file = xmalloc(strlen(file)+1);
+      strcpy(mpl->out_file, file);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- write_char - write next character to output text file.
+--
+-- This routine writes an ASCII character to the output text file. */
+
+void write_char(MPL *mpl, int c)
+{     xassert(mpl->out_fp != NULL);
+      if (mpl->out_fp == (void *)stdout)
+         xprintf("%c", c);
+      else
+         xfprintf(mpl->out_fp, "%c", c);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- write_text - format and write text to output text file.
+--
+-- This routine formats a text using the format control string and then
+-- writes this text to the output text file. */
+
+void write_text(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char buf[OUTBUF_SIZE], *c;
+      va_start(arg, fmt);
+      vsprintf(buf, fmt, arg);
+      xassert(strlen(buf) < sizeof(buf));
+      va_end(arg);
+      for (c = buf; *c != '\0'; c++) write_char(mpl, *c);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- flush_output - finalize writing data to output text file.
+--
+-- This routine finalizes writing data to the output text file. */
+
+void flush_output(MPL *mpl)
+{     xassert(mpl->out_fp != NULL);
+      if (mpl->out_fp != (void *)stdout)
+      {  xfflush(mpl->out_fp);
+         if (xferror(mpl->out_fp))
+            error(mpl, "write error on %s - %s", mpl->out_file,
+               xerrmsg());
+      }
+      return;
+}
+
+/**********************************************************************/
+/* * *                      SOLVER INTERFACE                      * * */
+/**********************************************************************/
+
+/*----------------------------------------------------------------------
+-- error - print error message and terminate model processing.
+--
+-- This routine formats and prints an error message and then terminates
+-- model processing. */
+
+void error(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char msg[4095+1];
+      va_start(arg, fmt);
+      vsprintf(msg, fmt, arg);
+      xassert(strlen(msg) < sizeof(msg));
+      va_end(arg);
+      switch (mpl->phase)
+      {  case 1:
+         case 2:
+            /* translation phase */
+            xprintf("%s:%d: %s\n",
+               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
+               mpl->line, msg);
+            print_context(mpl);
+            break;
+         case 3:
+            /* generation/postsolve phase */
+            xprintf("%s:%d: %s\n",
+               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
+               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      mpl->phase = 4;
+      longjmp(mpl->jump, 1);
+      /* no return */
+}
+
+/*----------------------------------------------------------------------
+-- warning - print warning message and continue model processing.
+--
+-- This routine formats and prints a warning message and returns to the
+-- calling program. */
+
+void warning(MPL *mpl, char *fmt, ...)
+{     va_list arg;
+      char msg[4095+1];
+      va_start(arg, fmt);
+      vsprintf(msg, fmt, arg);
+      xassert(strlen(msg) < sizeof(msg));
+      va_end(arg);
+      switch (mpl->phase)
+      {  case 1:
+         case 2:
+            /* translation phase */
+            xprintf("%s:%d: warning: %s\n",
+               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
+               mpl->line, msg);
+            break;
+         case 3:
+            /* generation/postsolve phase */
+            xprintf("%s:%d: warning: %s\n",
+               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
+               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_initialize - create and initialize translator database.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- MPL *mpl_initialize(void);
+--
+-- *Description*
+--
+-- The routine mpl_initialize creates and initializes the database used
+-- by the GNU MathProg translator.
+--
+-- *Returns*
+--
+-- The routine returns a pointer to the database created. */
+
+MPL *mpl_initialize(void)
+{     MPL *mpl;
+      mpl = xmalloc(sizeof(MPL));
+      /* scanning segment */
+      mpl->line = 0;
+      mpl->c = 0;
+      mpl->token = 0;
+      mpl->imlen = 0;
+      mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char));
+      mpl->image[0] = '\0';
+      mpl->value = 0.0;
+      mpl->b_token = 0;
+      mpl->b_imlen = 0;
+      mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char));
+      mpl->b_image[0] = '\0';
+      mpl->b_value = 0.0;
+      mpl->f_dots = 0;
+      mpl->f_scan = 0;
+      mpl->f_token = 0;
+      mpl->f_imlen = 0;
+      mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char));
+      mpl->f_image[0] = '\0';
+      mpl->f_value = 0.0;
+      mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char));
+      memset(mpl->context, ' ', CONTEXT_SIZE);
+      mpl->c_ptr = 0;
+      mpl->flag_d = 0;
+      /* translating segment */
+      mpl->pool = dmp_create_poolx(0);
+      mpl->tree = avl_create_tree(avl_strcmp, NULL);
+      mpl->model = NULL;
+      mpl->flag_x = 0;
+      mpl->as_within = 0;
+      mpl->as_in = 0;
+      mpl->as_binary = 0;
+      mpl->flag_s = 0;
+      /* common segment */
+      mpl->strings = dmp_create_poolx(sizeof(STRING));
+      mpl->symbols = dmp_create_poolx(sizeof(SYMBOL));
+      mpl->tuples = dmp_create_poolx(sizeof(TUPLE));
+      mpl->arrays = dmp_create_poolx(sizeof(ARRAY));
+      mpl->members = dmp_create_poolx(sizeof(MEMBER));
+      mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR));
+      mpl->formulae = dmp_create_poolx(sizeof(FORMULA));
+      mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON));
+      mpl->a_list = NULL;
+      mpl->sym_buf = xcalloc(255+1, sizeof(char));
+      mpl->sym_buf[0] = '\0';
+      mpl->tup_buf = xcalloc(255+1, sizeof(char));
+      mpl->tup_buf[0] = '\0';
+      /* generating/postsolving segment */
+      mpl->rand = rng_create_rand();
+      mpl->flag_p = 0;
+      mpl->stmt = NULL;
+#if 1 /* 11/II-2008 */
+      mpl->dca = NULL;
+#endif
+      mpl->m = 0;
+      mpl->n = 0;
+      mpl->row = NULL;
+      mpl->col = NULL;
+      /* input/output segment */
+      mpl->in_fp = NULL;
+      mpl->in_file = NULL;
+      mpl->out_fp = NULL;
+      mpl->out_file = NULL;
+      mpl->prt_fp = NULL;
+      mpl->prt_file = NULL;
+      /* solver interface segment */
+      if (setjmp(mpl->jump)) xassert(mpl != mpl);
+      mpl->phase = 0;
+      mpl->mod_file = NULL;
+      mpl->mpl_buf = xcalloc(255+1, sizeof(char));
+      mpl->mpl_buf[0] = '\0';
+      return mpl;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_read_model - read model section and optional data section.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_read_model(MPL *mpl, char *file, int skip_data);
+--
+-- *Description*
+--
+-- The routine mpl_read_model reads model section and optionally data
+-- section, which may follow the model section, from the text file,
+-- whose name is the character string file, performs translating model
+-- statements and data blocks, and stores all the information in the
+-- translator database.
+--
+-- The parameter skip_data is a flag. If the input file contains the
+-- data section and this flag is set, the data section is not read as
+-- if there were no data section and a warning message is issued. This
+-- allows reading the data section from another input file.
+--
+-- This routine should be called once after the routine mpl_initialize
+-- and before other API routines.
+--
+-- *Returns*
+--
+-- The routine mpl_read_model returns one the following codes:
+--
+-- 1 - translation successful. The input text file contains only model
+--     section. In this case the calling program may call the routine
+--     mpl_read_data to read data section from another file.
+-- 2 - translation successful. The input text file contains both model
+--     and data section.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_read_model(MPL *mpl, char *file, int skip_data)
+{     if (mpl->phase != 0)
+         xfault("mpl_read_model: invalid call sequence\n");
+      if (file == NULL)
+         xfault("mpl_read_model: no input filename specified\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* translate model section */
+      mpl->phase = 1;
+      xprintf("Reading model section from %s...\n", file);
+      open_input(mpl, file);
+      model_section(mpl);
+      if (mpl->model == NULL)
+         error(mpl, "empty model section not allowed");
+      /* save name of the input text file containing model section for
+         error diagnostics during the generation phase */
+      mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char));
+      strcpy(mpl->mod_file, mpl->in_file);
+      /* allocate content arrays for all model objects */
+      alloc_content(mpl);
+      /* optional data section may begin with the keyword 'data' */
+      if (is_keyword(mpl, "data"))
+      {  if (skip_data)
+         {  warning(mpl, "data section ignored");
+            goto skip;
+         }
+         mpl->flag_d = 1;
+         get_token(mpl /* data */);
+         if (mpl->token != T_SEMICOLON)
+            error(mpl, "semicolon missing where expected");
+         get_token(mpl /* ; */);
+         /* translate data section */
+         mpl->phase = 2;
+         xprintf("Reading data section from %s...\n", file);
+         data_section(mpl);
+      }
+      /* process end statement */
+      end_statement(mpl);
+skip: xprintf("%d line%s were read\n",
+         mpl->line, mpl->line == 1 ? "" : "s");
+      close_input(mpl);
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_read_data - read data section.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_read_data(MPL *mpl, char *file);
+--
+-- *Description*
+--
+-- The routine mpl_read_data reads data section from the text file,
+-- whose name is the character string file, performs translating data
+-- blocks, and stores the data read in the translator database.
+--
+-- If this routine is used, it should be called once after the routine
+-- mpl_read_model and if the latter returned the code 1.
+--
+-- *Returns*
+--
+-- The routine mpl_read_data returns one of the following codes:
+--
+-- 2 - data section has been successfully processed.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_read_data(MPL *mpl, char *file)
+#if 0 /* 02/X-2008 */
+{     if (mpl->phase != 1)
+#else
+{     if (!(mpl->phase == 1 || mpl->phase == 2))
+#endif
+         xfault("mpl_read_data: invalid call sequence\n");
+      if (file == NULL)
+         xfault("mpl_read_data: no input filename specified\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* process data section */
+      mpl->phase = 2;
+      xprintf("Reading data section from %s...\n", file);
+      mpl->flag_d = 1;
+      open_input(mpl, file);
+      /* in this case the keyword 'data' is optional */
+      if (is_literal(mpl, "data"))
+      {  get_token(mpl /* data */);
+         if (mpl->token != T_SEMICOLON)
+            error(mpl, "semicolon missing where expected");
+         get_token(mpl /* ; */);
+      }
+      data_section(mpl);
+      /* process end statement */
+      end_statement(mpl);
+      xprintf("%d line%s were read\n",
+         mpl->line, mpl->line == 1 ? "" : "s");
+      close_input(mpl);
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_generate - generate model.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_generate(MPL *mpl, char *file);
+--
+-- *Description*
+--
+-- The routine mpl_generate generates the model using its description
+-- stored in the translator database. This phase means generating all
+-- variables, constraints, and objectives, executing check and display
+-- statements, which precede the solve statement (if it is presented),
+-- and building the problem instance.
+--
+-- The character string file specifies the name of output text file, to
+-- which output produced by display statements should be written. It is
+-- allowed to specify NULL, in which case the output goes to stdout via
+-- the routine print.
+--
+-- This routine should be called once after the routine mpl_read_model
+-- or mpl_read_data and if one of the latters returned the code 2.
+--
+-- *Returns*
+--
+-- The routine mpl_generate returns one of the following codes:
+--
+-- 3 - model has been successfully generated. In this case the calling
+--     program may call other api routines to obtain components of the
+--     problem instance from the translator database.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_generate(MPL *mpl, char *file)
+{     if (!(mpl->phase == 1 || mpl->phase == 2))
+         xfault("mpl_generate: invalid call sequence\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* generate model */
+      mpl->phase = 3;
+      open_output(mpl, file);
+      generate_model(mpl);
+      flush_output(mpl);
+      /* build problem instance */
+      build_problem(mpl);
+      /* generation phase has been finished */
+      xprintf("Model has been successfully generated\n");
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_prob_name - obtain problem (model) name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_prob_name(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_prob_name returns a pointer to internal buffer,
+-- which contains symbolic name of the problem (model).
+--
+-- *Note*
+--
+-- Currently MathProg has no feature to assign a symbolic name to the
+-- model. Therefore the routine mpl_get_prob_name tries to construct
+-- such name using the name of input text file containing model section,
+-- although this is not a good idea (due to portability problems). */
+
+char *mpl_get_prob_name(MPL *mpl)
+{     char *name = mpl->mpl_buf;
+      char *file = mpl->mod_file;
+      int k;
+      if (mpl->phase != 3)
+         xfault("mpl_get_prob_name: invalid call sequence\n");
+      for (;;)
+      {  if (strchr(file, '/') != NULL)
+            file = strchr(file, '/') + 1;
+         else if (strchr(file, '\\') != NULL)
+            file = strchr(file, '\\') + 1;
+         else if (strchr(file, ':') != NULL)
+            file = strchr(file, ':') + 1;
+         else
+            break;
+      }
+      for (k = 0; ; k++)
+      {  if (k == 255) break;
+         if (!(isalnum((unsigned char)*file) || *file == '_')) break;
+         name[k] = *file++;
+      }
+      if (k == 0)
+         strcpy(name, "Unknown");
+      else
+         name[k] = '\0';
+      xassert(strlen(name) <= 255);
+      return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_num_rows - determine number of rows.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_num_rows(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_num_rows returns total number of rows in the
+-- problem, where each row is an individual constraint or objective. */
+
+int mpl_get_num_rows(MPL *mpl)
+{     if (mpl->phase != 3)
+         xfault("mpl_get_num_rows: invalid call sequence\n");
+      return mpl->m;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_num_cols - determine number of columns.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_num_cols(MPL *mpl);
+--
+-- *Returns*
+--
+-- The routine mpl_get_num_cols returns total number of columns in the
+-- problem, where each column is an individual variable. */
+
+int mpl_get_num_cols(MPL *mpl)
+{     if (mpl->phase != 3)
+         xfault("mpl_get_num_cols: invalid call sequence\n");
+      return mpl->n;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_name - obtain row name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_row_name(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_name returns a pointer to internal buffer,
+-- which contains symbolic name of i-th row of the problem. */
+
+char *mpl_get_row_name(MPL *mpl, int i)
+{     char *name = mpl->mpl_buf, *t;
+      int len;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_name: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_name: i = %d; row number out of range\n",
+            i);
+      strcpy(name, mpl->row[i]->con->name);
+      len = strlen(name);
+      xassert(len <= 255);
+      t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple);
+      while (*t)
+      {  if (len == 255) break;
+         name[len++] = *t++;
+      }
+      name[len] = '\0';
+      if (len == 255) strcpy(name+252, "...");
+      xassert(strlen(name) <= 255);
+      return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_kind - determine row kind.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_row_kind(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_kind returns the kind of i-th row, which can
+-- be one of the following:
+--
+-- MPL_ST  - non-free (constraint) row;
+-- MPL_MIN - free (objective) row to be minimized;
+-- MPL_MAX - free (objective) row to be maximized. */
+
+int mpl_get_row_kind(MPL *mpl, int i)
+{     int kind;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_kind: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_kind: i = %d; row number out of range\n",
+            i);
+      switch (mpl->row[i]->con->type)
+      {  case A_CONSTRAINT:
+            kind = MPL_ST; break;
+         case A_MINIMIZE:
+            kind = MPL_MIN; break;
+         case A_MAXIMIZE:
+            kind = MPL_MAX; break;
+         default:
+            xassert(mpl != mpl);
+      }
+      return kind;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_bnds - obtain row bounds.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
+--
+-- *Description*
+--
+-- The routine mpl_get_row_bnds stores lower and upper bounds of i-th
+-- row of the problem to the locations, which the parameters lb and ub
+-- point to, respectively. Besides the routine returns the type of the
+-- i-th row.
+--
+-- If some of the parameters lb and ub is NULL, the corresponding bound
+-- value is not stored.
+--
+-- Types and bounds have the following meaning:
+--
+--     Type           Bounds          Note
+--    -----------------------------------------------------------
+--    MPL_FR   -inf <  f(x) <  +inf   Free linear form
+--    MPL_LO     lb <= f(x) <  +inf   Inequality f(x) >= lb
+--    MPL_UP   -inf <  f(x) <=  ub    Inequality f(x) <= ub
+--    MPL_DB     lb <= f(x) <=  ub    Inequality lb <= f(x) <= ub
+--    MPL_FX           f(x)  =  lb    Equality f(x) = lb
+--
+-- where f(x) is the corresponding linear form of the i-th row.
+--
+-- If the row has no lower bound, *lb is set to zero; if the row has
+-- no upper bound, *ub is set to zero; and if the row is of fixed type,
+-- both *lb and *ub are set to the same value.
+--
+-- *Returns*
+--
+-- The routine returns the type of the i-th row as it is stated in the
+-- table above. */
+
+int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub)
+{     ELEMCON *con;
+      int type;
+      double lb, ub;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_bnds: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_bnds: i = %d; row number out of range\n",
+            i);
+      con = mpl->row[i];
+#if 0 /* 21/VII-2006 */
+      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (con->con->ubnd == NULL)
+         type = MPL_LO, lb = con->lbnd, ub = 0.0;
+      else if (con->con->lbnd == NULL)
+         type = MPL_UP, lb = 0.0, ub = con->ubnd;
+      else if (con->con->lbnd != con->con->ubnd)
+         type = MPL_DB, lb = con->lbnd, ub = con->ubnd;
+      else
+         type = MPL_FX, lb = ub = con->lbnd;
+#else
+      lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd);
+      ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd);
+      if (lb == -DBL_MAX && ub == +DBL_MAX)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (ub == +DBL_MAX)
+         type = MPL_LO, ub = 0.0;
+      else if (lb == -DBL_MAX)
+         type = MPL_UP, lb = 0.0;
+      else if (con->con->lbnd != con->con->ubnd)
+         type = MPL_DB;
+      else
+         type = MPL_FX;
+#endif
+      if (_lb != NULL) *_lb = lb;
+      if (_ub != NULL) *_ub = ub;
+      return type;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_mat_row - obtain row of the constraint matrix.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
+--
+-- *Description*
+--
+-- The routine mpl_get_mat_row stores column indices and numeric values
+-- of constraint coefficients for the i-th row to locations ndx[1], ...,
+-- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
+-- is number of (structural) non-zero constraint coefficients, and n is
+-- number of columns in the problem.
+--
+-- If the parameter ndx is NULL, column indices are not stored. If the
+-- parameter val is NULL, numeric values are not stored.
+--
+-- Note that free rows may have constant terms, which are not part of
+-- the constraint matrix and therefore not reported by this routine. The
+-- constant term of a particular row can be obtained, if necessary, via
+-- the routine mpl_get_row_c0.
+--
+-- *Returns*
+--
+-- The routine mpl_get_mat_row returns len, which is length of i-th row
+-- of the constraint matrix (i.e. number of non-zero coefficients). */
+
+int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[])
+{     FORMULA *term;
+      int len = 0;
+      if (mpl->phase != 3)
+         xfault("mpl_get_mat_row: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_mat_row: i = %d; row number out of range\n",
+            i);
+      for (term = mpl->row[i]->form; term != NULL; term = term->next)
+      {  xassert(term->var != NULL);
+         len++;
+         xassert(len <= mpl->n);
+         if (ndx != NULL) ndx[len] = term->var->j;
+         if (val != NULL) val[len] = term->coef;
+      }
+      return len;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_row_c0 - obtain constant term of free row.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- double mpl_get_row_c0(MPL *mpl, int i);
+--
+-- *Returns*
+--
+-- The routine mpl_get_row_c0 returns numeric value of constant term of
+-- i-th row.
+--
+-- Note that only free rows may have non-zero constant terms. Therefore
+-- if i-th row is not free, the routine returns zero. */
+
+double mpl_get_row_c0(MPL *mpl, int i)
+{     ELEMCON *con;
+      double c0;
+      if (mpl->phase != 3)
+         xfault("mpl_get_row_c0: invalid call sequence\n");
+      if (!(1 <= i && i <= mpl->m))
+         xfault("mpl_get_row_c0: i = %d; row number out of range\n",
+            i);
+      con = mpl->row[i];
+      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
+         c0 = - con->lbnd;
+      else
+         c0 = 0.0;
+      return c0;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_name - obtain column name.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- char *mpl_get_col_name(MPL *mpl, int j);
+--
+-- *Returns*
+--
+-- The routine mpl_get_col_name returns a pointer to internal buffer,
+-- which contains symbolic name of j-th column of the problem. */
+
+char *mpl_get_col_name(MPL *mpl, int j)
+{     char *name = mpl->mpl_buf, *t;
+      int len;
+      if (mpl->phase != 3)
+         xfault("mpl_get_col_name: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault("mpl_get_col_name: j = %d; column number out of range\n"
+            , j);
+      strcpy(name, mpl->col[j]->var->name);
+      len = strlen(name);
+      xassert(len <= 255);
+      t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple);
+      while (*t)
+      {  if (len == 255) break;
+         name[len++] = *t++;
+      }
+      name[len] = '\0';
+      if (len == 255) strcpy(name+252, "...");
+      xassert(strlen(name) <= 255);
+      return name;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_kind - determine column kind.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_col_kind(MPL *mpl, int j);
+--
+-- *Returns*
+--
+-- The routine mpl_get_col_kind returns the kind of j-th column, which
+-- can be one of the following:
+--
+-- MPL_NUM - continuous variable;
+-- MPL_INT - integer variable;
+-- MPL_BIN - binary variable.
+--
+-- Note that column kinds are defined independently on type and bounds
+-- (reported by the routine mpl_get_col_bnds) of corresponding columns.
+-- This means, in particular, that bounds of an integer column may be
+-- fractional, or a binary column may have lower and upper bounds that
+-- are not 0 and 1 (or it may have no lower/upper bound at all). */
+
+int mpl_get_col_kind(MPL *mpl, int j)
+{     int kind;
+      if (mpl->phase != 3)
+         xfault("mpl_get_col_kind: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault("mpl_get_col_kind: j = %d; column number out of range\n"
+            , j);
+      switch (mpl->col[j]->var->type)
+      {  case A_NUMERIC:
+            kind = MPL_NUM; break;
+         case A_INTEGER:
+            kind = MPL_INT; break;
+         case A_BINARY:
+            kind = MPL_BIN; break;
+         default:
+            xassert(mpl != mpl);
+      }
+      return kind;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_get_col_bnds - obtain column bounds.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
+--
+-- *Description*
+--
+-- The routine mpl_get_col_bnds stores lower and upper bound of j-th
+-- column of the problem to the locations, which the parameters lb and
+-- ub point to, respectively. Besides the routine returns the type of
+-- the j-th column.
+--
+-- If some of the parameters lb and ub is NULL, the corresponding bound
+-- value is not stored.
+--
+-- Types and bounds have the following meaning:
+--
+--     Type         Bounds         Note
+--    ------------------------------------------------------
+--    MPL_FR   -inf <  x <  +inf   Free (unbounded) variable
+--    MPL_LO     lb <= x <  +inf   Variable with lower bound
+--    MPL_UP   -inf <  x <=  ub    Variable with upper bound
+--    MPL_DB     lb <= x <=  ub    Double-bounded variable
+--    MPL_FX           x  =  lb    Fixed variable
+--
+-- where x is individual variable corresponding to the j-th column.
+--
+-- If the column has no lower bound, *lb is set to zero; if the column
+-- has no upper bound, *ub is set to zero; and if the column is of fixed
+-- type, both *lb and *ub are set to the same value.
+--
+-- *Returns*
+--
+-- The routine returns the type of the j-th column as it is stated in
+-- the table above. */
+
+int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub)
+{     ELEMVAR *var;
+      int type;
+      double lb, ub;
+      if (mpl->phase != 3)
+         xfault("mpl_get_col_bnds: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault("mpl_get_col_bnds: j = %d; column number out of range\n"
+            , j);
+      var = mpl->col[j];
+#if 0 /* 21/VII-2006 */
+      if (var->var->lbnd == NULL && var->var->ubnd == NULL)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (var->var->ubnd == NULL)
+         type = MPL_LO, lb = var->lbnd, ub = 0.0;
+      else if (var->var->lbnd == NULL)
+         type = MPL_UP, lb = 0.0, ub = var->ubnd;
+      else if (var->var->lbnd != var->var->ubnd)
+         type = MPL_DB, lb = var->lbnd, ub = var->ubnd;
+      else
+         type = MPL_FX, lb = ub = var->lbnd;
+#else
+      lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd);
+      ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd);
+      if (lb == -DBL_MAX && ub == +DBL_MAX)
+         type = MPL_FR, lb = ub = 0.0;
+      else if (ub == +DBL_MAX)
+         type = MPL_LO, ub = 0.0;
+      else if (lb == -DBL_MAX)
+         type = MPL_UP, lb = 0.0;
+      else if (var->var->lbnd != var->var->ubnd)
+         type = MPL_DB;
+      else
+         type = MPL_FX;
+#endif
+      if (_lb != NULL) *_lb = lb;
+      if (_ub != NULL) *_ub = ub;
+      return type;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_has_solve_stmt - check if model has solve statement.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_has_solve_stmt(MPL *mpl);
+--
+-- *Returns*
+--
+-- If the model has the solve statement, the routine returns non-zero,
+-- otherwise zero is returned. */
+
+int mpl_has_solve_stmt(MPL *mpl)
+{     if (mpl->phase != 3)
+         xfault("mpl_has_solve_stmt: invalid call sequence\n");
+      return mpl->flag_s;
+}
+
+#if 1 /* 15/V-2010 */
+void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
+      double dual)
+{     /* store row (constraint/objective) solution components */
+      xassert(mpl->phase == 3);
+      xassert(1 <= i && i <= mpl->m);
+      mpl->row[i]->stat = stat;
+      mpl->row[i]->prim = prim;
+      mpl->row[i]->dual = dual;
+      return;
+}
+#endif
+
+#if 1 /* 15/V-2010 */
+void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
+      double dual)
+{     /* store column (variable) solution components */
+      xassert(mpl->phase == 3);
+      xassert(1 <= j && j <= mpl->n);
+      mpl->col[j]->stat = stat;
+      mpl->col[j]->prim = prim;
+      mpl->col[j]->dual = dual;
+      return;
+}
+#endif
+
+#if 0 /* 15/V-2010 */
+/*----------------------------------------------------------------------
+-- mpl_put_col_value - store column value.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- void mpl_put_col_value(MPL *mpl, int j, double val);
+--
+-- *Description*
+--
+-- The routine mpl_put_col_value stores numeric value of j-th column
+-- into the translator database. It is assumed that the column value is
+-- provided by the solver. */
+
+void mpl_put_col_value(MPL *mpl, int j, double val)
+{     if (mpl->phase != 3)
+         xfault("mpl_put_col_value: invalid call sequence\n");
+      if (!(1 <= j && j <= mpl->n))
+         xfault(
+         "mpl_put_col_value: j = %d; column number out of range\n", j);
+      mpl->col[j]->prim = val;
+      return;
+}
+#endif
+
+/*----------------------------------------------------------------------
+-- mpl_postsolve - postsolve model.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- int mpl_postsolve(MPL *mpl);
+--
+-- *Description*
+--
+-- The routine mpl_postsolve performs postsolving of the model using
+-- its description stored in the translator database. This phase means
+-- executing statements, which follow the solve statement.
+--
+-- If this routine is used, it should be called once after the routine
+-- mpl_generate and if the latter returned the code 3.
+--
+-- *Returns*
+--
+-- The routine mpl_postsolve returns one of the following codes:
+--
+-- 3 - model has been successfully postsolved.
+-- 4 - processing failed due to some errors. In this case the calling
+--     program should call the routine mpl_terminate to terminate model
+--     processing. */
+
+int mpl_postsolve(MPL *mpl)
+{     if (!(mpl->phase == 3 && !mpl->flag_p))
+         xfault("mpl_postsolve: invalid call sequence\n");
+      /* set up error handler */
+      if (setjmp(mpl->jump)) goto done;
+      /* perform postsolving */
+      postsolve_model(mpl);
+      flush_output(mpl);
+      /* postsolving phase has been finished */
+      xprintf("Model has been successfully processed\n");
+done: /* return to the calling program */
+      return mpl->phase;
+}
+
+/*----------------------------------------------------------------------
+-- mpl_terminate - free all resources used by translator.
+--
+-- *Synopsis*
+--
+-- #include "glpmpl.h"
+-- void mpl_terminate(MPL *mpl);
+--
+-- *Description*
+--
+-- The routine mpl_terminate frees all the resources used by the GNU
+-- MathProg translator. */
+
+void mpl_terminate(MPL *mpl)
+{     if (setjmp(mpl->jump)) xassert(mpl != mpl);
+      switch (mpl->phase)
+      {  case 0:
+         case 1:
+         case 2:
+         case 3:
+            /* there were no errors; clean the model content */
+            clean_model(mpl);
+            xassert(mpl->a_list == NULL);
+#if 1 /* 11/II-2008 */
+            xassert(mpl->dca == NULL);
+#endif
+            break;
+         case 4:
+            /* model processing has been finished due to error; delete
+               search trees, which may be created for some arrays */
+            {  ARRAY *a;
+               for (a = mpl->a_list; a != NULL; a = a->next)
+                  if (a->tree != NULL) avl_delete_tree(a->tree);
+            }
+#if 1 /* 11/II-2008 */
+            free_dca(mpl);
+#endif
+            break;
+         default:
+            xassert(mpl != mpl);
+      }
+      /* delete the translator database */
+      xfree(mpl->image);
+      xfree(mpl->b_image);
+      xfree(mpl->f_image);
+      xfree(mpl->context);
+      dmp_delete_pool(mpl->pool);
+      avl_delete_tree(mpl->tree);
+      dmp_delete_pool(mpl->strings);
+      dmp_delete_pool(mpl->symbols);
+      dmp_delete_pool(mpl->tuples);
+      dmp_delete_pool(mpl->arrays);
+      dmp_delete_pool(mpl->members);
+      dmp_delete_pool(mpl->elemvars);
+      dmp_delete_pool(mpl->formulae);
+      dmp_delete_pool(mpl->elemcons);
+      xfree(mpl->sym_buf);
+      xfree(mpl->tup_buf);
+      rng_delete_rand(mpl->rand);
+      if (mpl->row != NULL) xfree(mpl->row);
+      if (mpl->col != NULL) xfree(mpl->col);
+      if (mpl->in_fp != NULL) xfclose(mpl->in_fp);
+      if (mpl->out_fp != NULL && mpl->out_fp != (void *)stdout)
+         xfclose(mpl->out_fp);
+      if (mpl->out_file != NULL) xfree(mpl->out_file);
+      if (mpl->prt_fp != NULL) xfclose(mpl->prt_fp);
+      if (mpl->prt_file != NULL) xfree(mpl->prt_file);
+      if (mpl->mod_file != NULL) xfree(mpl->mod_file);
+      xfree(mpl->mpl_buf);
+      xfree(mpl);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpmpl05.c
===================================================================
--- deps/glpk/src/glpmpl05.c	(revision 9)
+++ deps/glpk/src/glpmpl05.c	(revision 9)
@@ -0,0 +1,562 @@
+/* glpmpl05.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Authors: Andrew Makhorin <mao@gnu.org>
+*           Heinrich Schuchardt <xypron.glpk@gmx.de>
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_STDIO
+#define _GLPSTD_TIME
+#include "glpmpl.h"
+
+double fn_gmtime(MPL *mpl)
+{     /* obtain the current calendar time (UTC) */
+      time_t timer;
+      struct tm *tm;
+      int j;
+      time(&timer);
+      if (timer == (time_t)(-1))
+err:     error(mpl, "gmtime(); unable to obtain current calendar time");
+      tm = gmtime(&timer);
+      if (tm == NULL) goto err;
+      j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+      if (j < 0) goto err;
+      return (((double)(j - jday(1, 1, 1970)) * 24.0 +
+         (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 +
+         (double)tm->tm_sec;
+}
+
+static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday",
+      "Friday", "Saturday", "Sunday" };
+
+static char *moon[] = { "January", "February", "March", "April", "May",
+      "June", "July", "August", "September", "October", "November",
+      "December" };
+
+static void error1(MPL *mpl, const char *str, const char *s,
+      const char *fmt, const char *f, const char *msg)
+{     xprintf("Input string passed to str2time:\n");
+      xprintf("%s\n", str);
+      xprintf("%*s\n", (s - str) + 1, "^");
+      xprintf("Format string passed to str2time:\n");
+      xprintf("%s\n", fmt);
+      xprintf("%*s\n", (f - fmt) + 1, "^");
+      error(mpl, "%s", msg);
+      /* no return */
+}
+
+double fn_str2time(MPL *mpl, const char *str, const char *fmt)
+{     /* convert character string to the calendar time */
+      int j, year, month, day, hh, mm, ss, zone;
+      const char *s, *f;
+      year = month = day = hh = mm = ss = -1, zone = INT_MAX;
+      s = str;
+      for (f = fmt; *f != '\0'; f++)
+      {  if (*f == '%')
+         {  f++;
+            if (*f == 'b' || *f == 'h')
+            {  /* the abbreviated month name */
+               int k;
+               char *name;
+               if (month >= 0)
+                  error1(mpl, str, s, fmt, f, "month multiply specified"
+                     );
+               while (*s == ' ') s++;
+               for (month = 1; month <= 12; month++)
+               {  name = moon[month-1];
+                  for (k = 0; k <= 2; k++)
+                  {  if (toupper((unsigned char)s[k]) !=
+                         toupper((unsigned char)name[k])) goto next;
+                  }
+                  s += 3;
+                  for (k = 3; name[k] != '\0'; k++)
+                  {  if (toupper((unsigned char)*s) !=
+                         toupper((unsigned char)name[k])) break;
+                     s++;
+                  }
+                  break;
+next:             ;
+               }
+               if (month > 12)
+                  error1(mpl, str, s, fmt, f, "abbreviated month name m"
+                     "issing or invalid");
+            }
+            else if (*f == 'd')
+            {  /* the day of the month as a decimal number (01..31) */
+               if (day >= 0)
+                  error1(mpl, str, s, fmt, f, "day multiply specified");
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "day missing or invalid");
+               day = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  day = 10 * day + ((*s++) - '0');
+               if (!(1 <= day && day <= 31))
+                  error1(mpl, str, s, fmt, f, "day out of range");
+            }
+            else if (*f == 'H')
+            {  /* the hour as a decimal number, using a 24-hour clock
+                  (00..23) */
+               if (hh >= 0)
+                  error1(mpl, str, s, fmt, f, "hour multiply specified")
+                     ;
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "hour missing or invalid")
+                     ;
+               hh = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  hh = 10 * hh + ((*s++) - '0');
+               if (!(0 <= hh && hh <= 23))
+                  error1(mpl, str, s, fmt, f, "hour out of range");
+            }
+            else if (*f == 'm')
+            {  /* the month as a decimal number (01..12) */
+               if (month >= 0)
+                  error1(mpl, str, s, fmt, f, "month multiply specified"
+                     );
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "month missing or invalid"
+                     );
+               month = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  month = 10 * month + ((*s++) - '0');
+               if (!(1 <= month && month <= 12))
+                  error1(mpl, str, s, fmt, f, "month out of range");
+            }
+            else if (*f == 'M')
+            {  /* the minute as a decimal number (00..59) */
+               if (mm >= 0)
+                  error1(mpl, str, s, fmt, f, "minute multiply specifie"
+                     "d");
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "minute missing or invali"
+                     "d");
+               mm = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  mm = 10 * mm + ((*s++) - '0');
+               if (!(0 <= mm && mm <= 59))
+                  error1(mpl, str, s, fmt, f, "minute out of range");
+            }
+            else if (*f == 'S')
+            {  /* the second as a decimal number (00..60) */
+               if (ss >= 0)
+                  error1(mpl, str, s, fmt, f, "second multiply specifie"
+                     "d");
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "second missing or invali"
+                     "d");
+               ss = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  ss = 10 * ss + ((*s++) - '0');
+               if (!(0 <= ss && ss <= 60))
+                  error1(mpl, str, s, fmt, f, "second out of range");
+            }
+            else if (*f == 'y')
+            {  /* the year without a century as a decimal number
+                  (00..99); the values 00 to 68 mean the years 2000 to
+                  2068 while the values 69 to 99 mean the years 1969 to
+                  1999 */
+               if (year >= 0)
+                  error1(mpl, str, s, fmt, f, "year multiply specified")
+                     ;
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "year missing or invalid")
+                     ;
+               year = (*s++) - '0';
+               if ('0' <= *s && *s <= '9')
+                  year = 10 * year + ((*s++) - '0');
+               year += (year >= 69 ? 1900 : 2000);
+            }
+            else if (*f == 'Y')
+            {  /* the year as a decimal number, using the Gregorian
+                  calendar */
+               if (year >= 0)
+                  error1(mpl, str, s, fmt, f, "year multiply specified")
+                     ;
+               while (*s == ' ') s++;
+               if (!('0' <= *s && *s <= '9'))
+                  error1(mpl, str, s, fmt, f, "year missing or invalid")
+                     ;
+               year = 0;
+               for (j = 1; j <= 4; j++)
+               {  if (!('0' <= *s && *s <= '9')) break;
+                  year = 10 * year + ((*s++) - '0');
+               }
+               if (!(1 <= year && year <= 4000))
+                  error1(mpl, str, s, fmt, f, "year out of range");
+            }
+            else if (*f == 'z')
+            {  /* time zone offset in the form zhhmm */
+               int z, hh, mm;
+               if (zone != INT_MAX)
+                  error1(mpl, str, s, fmt, f, "time zone offset multipl"
+                     "y specified");
+               while (*s == ' ') s++;
+               if (*s == 'Z')
+               {  z = hh = mm = 0, s++;
+                  goto skip;
+               }
+               if (*s == '+')
+                  z = +1, s++;
+               else if (*s == '-')
+                  z = -1, s++;
+               else
+                  error1(mpl, str, s, fmt, f, "time zone offset sign mi"
+                     "ssing");
+               hh = 0;
+               for (j = 1; j <= 2; j++)
+               {  if (!('0' <= *s && *s <= '9'))
+err1:                error1(mpl, str, s, fmt, f, "time zone offset valu"
+                        "e incomplete or invalid");
+                  hh = 10 * hh + ((*s++) - '0');
+               }
+               if (hh > 23)
+err2:             error1(mpl, str, s, fmt, f, "time zone offset value o"
+                     "ut of range");
+               if (*s == ':')
+               {  s++;
+                  if (!('0' <= *s && *s <= '9')) goto err1;
+               }
+               mm = 0;
+               if (!('0' <= *s && *s <= '9')) goto skip;
+               for (j = 1; j <= 2; j++)
+               {  if (!('0' <= *s && *s <= '9')) goto err1;
+                  mm = 10 * mm + ((*s++) - '0');
+               }
+               if (mm > 59) goto err2;
+skip:          zone = z * (60 * hh + mm);
+            }
+            else if (*f == '%')
+            {  /* literal % character */
+               goto test;
+            }
+            else
+               error1(mpl, str, s, fmt, f, "invalid conversion specifie"
+                  "r");
+         }
+         else if (*f == ' ')
+            ;
+         else
+test:    {  /* check a matching character in the input string */
+            if (*s != *f)
+               error1(mpl, str, s, fmt, f, "character mismatch");
+            s++;
+         }
+      }
+      if (year < 0) year = 1970;
+      if (month < 0) month = 1;
+      if (day < 0) day = 1;
+      if (hh < 0) hh = 0;
+      if (mm < 0) mm = 0;
+      if (ss < 0) ss = 0;
+      if (zone == INT_MAX) zone = 0;
+      j = jday(day, month, year);
+      xassert(j >= 0);
+      return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) *
+         60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone;
+}
+
+static void error2(MPL *mpl, const char *fmt, const char *f,
+      const char *msg)
+{     xprintf("Format string passed to time2str:\n");
+      xprintf("%s\n", fmt);
+      xprintf("%*s\n", (f - fmt) + 1, "^");
+      error(mpl, "%s", msg);
+      /* no return */
+}
+
+static int weekday(int j)
+{     /* determine weekday number (1 = Mon, ..., 7 = Sun) */
+      return (j + jday(1, 1, 1970)) % 7 + 1;
+}
+
+static int firstday(int year)
+{     /* determine the first day of the first week for a specified year
+         according to ISO 8601 */
+      int j;
+      /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is
+         in week 01; if 1 January is Friday, Saturday or Sunday, it is
+         in week 52 or 53 of the previous year */
+      j = jday(1, 1, year) - jday(1, 1, 1970);
+      switch (weekday(j))
+      {  case 1: /* 1 Jan is Mon */ j += 0; break;
+         case 2: /* 1 Jan is Tue */ j -= 1; break;
+         case 3: /* 1 Jan is Wed */ j -= 2; break;
+         case 4: /* 1 Jan is Thu */ j -= 3; break;
+         case 5: /* 1 Jan is Fri */ j += 3; break;
+         case 6: /* 1 Jan is Sat */ j += 2; break;
+         case 7: /* 1 Jan is Sun */ j += 1; break;
+         default: xassert(j != j);
+      }
+      /* the first day of the week must be Monday */
+      xassert(weekday(j) == 1);
+      return j;
+}
+
+void fn_time2str(MPL *mpl, char *str, double t, const char *fmt)
+{     /* convert the calendar time to character string */
+      int j, year, month, day, hh, mm, ss, len;
+      double temp;
+      const char *f;
+      char buf[MAX_LENGTH+1];
+      if (!(-62135596800.0 <= t && t <= 64092211199.0))
+         error(mpl, "time2str(%.*g,...); argument out of range",
+            DBL_DIG, t);
+      t = floor(t + 0.5);
+      temp = fabs(t) / 86400.0;
+      j = (int)floor(temp);
+      if (t < 0.0)
+      {  if (temp == floor(temp))
+            j = - j;
+         else
+            j = - (j + 1);
+      }
+      xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0);
+      ss = (int)(t - 86400.0 * (double)j);
+      xassert(0 <= ss && ss < 86400);
+      mm = ss / 60, ss %= 60;
+      hh = mm / 60, mm %= 60;
+      len = 0;
+      for (f = fmt; *f != '\0'; f++)
+      {  if (*f == '%')
+         {  f++;
+            if (*f == 'a')
+            {  /* the abbreviated weekday name */
+               memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0';
+            }
+            else if (*f == 'A')
+            {  /* the full weekday name */
+               strcpy(buf, week[weekday(j)-1]);
+            }
+            else if (*f == 'b' || *f == 'h')
+            {  /* the abbreviated month name */
+               memcpy(buf, moon[month-1], 3), buf[3] = '\0';
+            }
+            else if (*f == 'B')
+            {  /* the full month name */
+               strcpy(buf, moon[month-1]);
+            }
+            else if (*f == 'C')
+            {  /* the century of the year */
+               sprintf(buf, "%02d", year / 100);
+            }
+            else if (*f == 'd')
+            {  /* the day of the month as a decimal number (01..31) */
+               sprintf(buf, "%02d", day);
+            }
+            else if (*f == 'D')
+            {  /* the date using the format %m/%d/%y */
+               sprintf(buf, "%02d/%02d/%02d", month, day, year % 100);
+            }
+            else if (*f == 'e')
+            {  /* the day of the month like with %d, but padded with
+                  blank (1..31) */
+               sprintf(buf, "%2d", day);
+            }
+            else if (*f == 'F')
+            {  /* the date using the format %Y-%m-%d */
+               sprintf(buf, "%04d-%02d-%02d", year, month, day);
+            }
+            else if (*f == 'g')
+            {  /* the year corresponding to the ISO week number, but
+                  without the century (range 00 through 99); this has
+                  the same format and value as %y, except that if the
+                  ISO week number (see %V) belongs to the previous or
+                  next year, that year is used instead */
+               int iso;
+               if (j < firstday(year))
+                  iso = year - 1;
+               else if (j < firstday(year + 1))
+                  iso = year;
+               else
+                  iso = year + 1;
+               sprintf(buf, "%02d", iso % 100);
+            }
+            else if (*f == 'G')
+            {  /* the year corresponding to the ISO week number; this
+                  has the same format and value as %Y, excepth that if
+                  the ISO week number (see %V) belongs to the previous
+                  or next year, that year is used instead */
+               int iso;
+               if (j < firstday(year))
+                  iso = year - 1;
+               else if (j < firstday(year + 1))
+                  iso = year;
+               else
+                  iso = year + 1;
+               sprintf(buf, "%04d", iso);
+            }
+            else if (*f == 'H')
+            {  /* the hour as a decimal number, using a 24-hour clock
+                  (00..23) */
+               sprintf(buf, "%02d", hh);
+            }
+            else if (*f == 'I')
+            {  /* the hour as a decimal number, using a 12-hour clock
+                  (01..12) */
+               sprintf(buf, "%02d",
+                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
+            }
+            else if (*f == 'j')
+            {  /* the day of the year as a decimal number (001..366) */
+               sprintf(buf, "%03d",
+                  jday(day, month, year) - jday(1, 1, year) + 1);
+            }
+            else if (*f == 'k')
+            {  /* the hour as a decimal number, using a 24-hour clock
+                  like %H, but padded with blank (0..23) */
+               sprintf(buf, "%2d", hh);
+            }
+            else if (*f == 'l')
+            {  /* the hour as a decimal number, using a 12-hour clock
+                  like %I, but padded with blank (1..12) */
+               sprintf(buf, "%2d",
+                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12);
+            }
+            else if (*f == 'm')
+            {  /* the month as a decimal number (01..12) */
+               sprintf(buf, "%02d", month);
+            }
+            else if (*f == 'M')
+            {  /* the minute as a decimal number (00..59) */
+               sprintf(buf, "%02d", mm);
+            }
+            else if (*f == 'p')
+            {  /* either AM or PM, according to the given time value;
+                  noon is treated as PM and midnight as AM */
+               strcpy(buf, hh <= 11 ? "AM" : "PM");
+            }
+            else if (*f == 'P')
+            {  /* either am or pm, according to the given time value;
+                  noon is treated as pm and midnight as am */
+               strcpy(buf, hh <= 11 ? "am" : "pm");
+            }
+            else if (*f == 'r')
+            {  /* the calendar time using the format %I:%M:%S %p */
+               sprintf(buf, "%02d:%02d:%02d %s",
+                  hh == 0 ? 12 : hh <= 12 ? hh : hh - 12,
+                  mm, ss, hh <= 11 ? "AM" : "PM");
+            }
+            else if (*f == 'R')
+            {  /* the hour and minute using the format %H:%M */
+               sprintf(buf, "%02d:%02d", hh, mm);
+            }
+            else if (*f == 'S')
+            {  /* the second as a decimal number (00..59) */
+               sprintf(buf, "%02d", ss);
+            }
+            else if (*f == 'T')
+            {  /* the time of day using the format %H:%M:%S */
+               sprintf(buf, "%02d:%02d:%02d", hh, mm, ss);
+            }
+            else if (*f == 'u')
+            {  /* the day of the week as a decimal number (1..7),
+                  Monday being 1 */
+               sprintf(buf, "%d", weekday(j));
+            }
+            else if (*f == 'U')
+            {  /* the week number of the current year as a decimal
+                  number (range 00 through 53), starting with the first
+                  Sunday as the first day of the first week; days
+                  preceding the first Sunday in the year are considered
+                  to be in week 00 */
+#if 1 /* 09/I-2009 */
+#undef sun
+/* causes compilation error in SunOS */
+#endif
+               int sun;
+               /* sun = the first Sunday of the year */
+               sun = jday(1, 1, year) - jday(1, 1, 1970);
+               sun += (7 - weekday(sun));
+               sprintf(buf, "%02d", (j + 7 - sun) / 7);
+            }
+            else if (*f == 'V')
+            {  /* the ISO week number as a decimal number (range 01
+                  through 53); ISO weeks start with Monday and end with
+                  Sunday; week 01 of a year is the first week which has
+                  the majority of its days in that year; week 01 of
+                  a year can contain days from the previous year; the
+                  week before week 01 of a year is the last week (52 or
+                  53) of the previous year even if it contains days
+                  from the new year */
+               int iso;
+               if (j < firstday(year))
+                  iso = j - firstday(year - 1);
+               else if (j < firstday(year + 1))
+                  iso = j - firstday(year);
+               else
+                  iso = j - firstday(year + 1);
+               sprintf(buf, "%02d", iso / 7 + 1);
+            }
+            else if (*f == 'w')
+            {  /* the day of the week as a decimal number (0..6),
+                  Sunday being 0 */
+               sprintf(buf, "%d", weekday(j) % 7);
+            }
+            else if (*f == 'W')
+            {  /* the week number of the current year as a decimal
+                  number (range 00 through 53), starting with the first
+                  Monday as the first day of the first week; days
+                  preceding the first Monday in the year are considered
+                  to be in week 00 */
+               int mon;
+               /* mon = the first Monday of the year */
+               mon = jday(1, 1, year) - jday(1, 1, 1970);
+               mon += (8 - weekday(mon)) % 7;
+               sprintf(buf, "%02d", (j + 7 - mon) / 7);
+            }
+            else if (*f == 'y')
+            {  /* the year without a century as a decimal number
+                  (00..99) */
+               sprintf(buf, "%02d", year % 100);
+            }
+            else if (*f == 'Y')
+            {  /* the year as a decimal number, using the Gregorian
+                  calendar */
+               sprintf(buf, "%04d", year);
+            }
+            else if (*f == '%')
+            {  /* a literal % character */
+               buf[0] = '%', buf[1] = '\0';
+            }
+            else
+               error2(mpl, fmt, f, "invalid conversion specifier");
+         }
+         else
+            buf[0] = *f, buf[1] = '\0';
+         if (len + strlen(buf) > MAX_LENGTH)
+            error(mpl, "time2str; output string length exceeds %d chara"
+               "cters", MAX_LENGTH);
+         memcpy(str+len, buf, strlen(buf));
+         len += strlen(buf);
+      }
+      str[len] = '\0';
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpmpl06.c
===================================================================
--- deps/glpk/src/glpmpl06.c	(revision 9)
+++ deps/glpk/src/glpmpl06.c	(revision 9)
@@ -0,0 +1,1002 @@
+/* glpmpl06.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpmpl.h"
+#include "glpsql.h"
+
+/**********************************************************************/
+
+#define CSV_FIELD_MAX 50
+/* maximal number of fields in record */
+
+#define CSV_FDLEN_MAX 100
+/* maximal field length */
+
+struct csv
+{     /* comma-separated values file */
+      int mode;
+      /* 'R' = reading; 'W' = writing */
+      char *fname;
+      /* name of csv file */
+      FILE *fp;
+      /* stream assigned to csv file */
+      jmp_buf jump;
+      /* address for non-local go to in case of error */
+      int count;
+      /* record count */
+      /*--------------------------------------------------------------*/
+      /* used only for input csv file */
+      int c;
+      /* current character or EOF */
+      int what;
+      /* current marker: */
+#define CSV_EOF   0  /* end-of-file */
+#define CSV_EOR   1  /* end-of-record */
+#define CSV_NUM   2  /* floating-point number */
+#define CSV_STR   3  /* character string */
+      char field[CSV_FDLEN_MAX+1];
+      /* current field just read */
+      int nf;
+      /* number of fields in the csv file */
+      int ref[1+CSV_FIELD_MAX];
+      /* ref[k] = k', if k-th field of the csv file corresponds to
+         k'-th field in the table statement; if ref[k] = 0, k-th field
+         of the csv file is ignored */
+#if 1 /* 01/VI-2010 */
+      int nskip;
+      /* number of comment records preceding the header record */
+#endif
+};
+
+#undef read_char
+
+static void read_char(struct csv *csv)
+{     /* read character from csv data file */
+      int c;
+      xassert(csv->c != EOF);
+      if (csv->c == '\n') csv->count++;
+loop: c = fgetc(csv->fp);
+      if (ferror(csv->fp))
+      {  xprintf("%s:%d: read error - %s\n", csv->fname, csv->count,
+            strerror(errno));
+         longjmp(csv->jump, 0);
+      }
+      if (feof(csv->fp))
+      {  if (csv->c == '\n')
+         {  csv->count--;
+            c = EOF;
+         }
+         else
+         {  xprintf("%s:%d: warning: missing final end-of-line\n",
+               csv->fname, csv->count);
+            c = '\n';
+         }
+      }
+      else if (c == '\r')
+         goto loop;
+      else if (c == '\n')
+         ;
+      else if (iscntrl(c))
+      {  xprintf("%s:%d: invalid control character 0x%02X\n",
+            csv->fname, csv->count, c);
+         longjmp(csv->jump, 0);
+      }
+      csv->c = c;
+      return;
+}
+
+static void read_field(struct csv *csv)
+{     /* read field from csv data file */
+      /* check for end of file */
+      if (csv->c == EOF)
+      {  csv->what = CSV_EOF;
+         strcpy(csv->field, "EOF");
+         goto done;
+      }
+      /* check for end of record */
+      if (csv->c == '\n')
+      {  csv->what = CSV_EOR;
+         strcpy(csv->field, "EOR");
+         read_char(csv);
+         if (csv->c == ',')
+err1:    {  xprintf("%s:%d: empty field not allowed\n", csv->fname,
+               csv->count);
+            longjmp(csv->jump, 0);
+         }
+         if (csv->c == '\n')
+         {  xprintf("%s:%d: empty record not allowed\n", csv->fname,
+               csv->count);
+            longjmp(csv->jump, 0);
+         }
+#if 1 /* 01/VI-2010 */
+         /* skip comment records; may appear only before the very first
+            record containing field names */
+         if (csv->c == '#' && csv->count == 1)
+         {  while (csv->c == '#')
+            {  while (csv->c != '\n')
+                  read_char(csv);
+               read_char(csv);
+               csv->nskip++;
+            }
+         }
+#endif
+         goto done;
+      }
+      /* skip comma before next field */
+      if (csv->c == ',')
+         read_char(csv);
+      /* read field */
+      if (csv->c == '\'' || csv->c == '"')
+      {  /* read a field enclosed in quotes */
+         int quote = csv->c, len = 0;
+         csv->what = CSV_STR;
+         /* skip opening quote */
+         read_char(csv);
+         /* read field characters within quotes */
+         for (;;)
+         {  /* check for closing quote and read it */
+            if (csv->c == quote)
+            {  read_char(csv);
+               if (csv->c == quote)
+                  ;
+               else if (csv->c == ',' || csv->c == '\n')
+                  break;
+               else
+               {  xprintf("%s:%d: invalid field\n", csv->fname,
+                     csv->count);
+                  longjmp(csv->jump, 0);
+               }
+            }
+            /* check the current field length */
+            if (len == CSV_FDLEN_MAX)
+err2:       {  xprintf("%s:%d: field too long\n", csv->fname,
+                  csv->count);
+               longjmp(csv->jump, 0);
+            }
+            /* add the current character to the field */
+            csv->field[len++] = (char)csv->c;
+            /* read the next character */
+            read_char(csv);
+         }
+         /* the field has been read */
+         if (len == 0) goto err1;
+         csv->field[len] = '\0';
+      }
+      else
+      {  /* read a field not enclosed in quotes */
+         int len = 0;
+         double temp;
+         csv->what = CSV_NUM;
+         while (!(csv->c == ',' || csv->c == '\n'))
+         {  /* quotes within the field are not allowed */
+            if (csv->c == '\'' || csv->c == '"')
+            {  xprintf("%s:%d: invalid use of single or double quote wi"
+                  "thin field\n", csv->fname, csv->count);
+               longjmp(csv->jump, 0);
+            }
+            /* check the current field length */
+            if (len == CSV_FDLEN_MAX) goto err2;
+            /* add the current character to the field */
+            csv->field[len++] = (char)csv->c;
+            /* read the next character */
+            read_char(csv);
+         }
+         /* the field has been read */
+         if (len == 0) goto err1;
+         csv->field[len] = '\0';
+         /* check the field type */
+         if (str2num(csv->field, &temp)) csv->what = CSV_STR;
+      }
+done: return;
+}
+
+static struct csv *csv_open_file(TABDCA *dca, int mode)
+{     /* open csv data file */
+      struct csv *csv;
+      /* create control structure */
+      csv = xmalloc(sizeof(struct csv));
+      csv->mode = mode;
+      csv->fname = NULL;
+      csv->fp = NULL;
+      if (setjmp(csv->jump)) goto fail;
+      csv->count = 0;
+      csv->c = '\n';
+      csv->what = 0;
+      csv->field[0] = '\0';
+      csv->nf = 0;
+      /* try to open the csv data file */
+      if (mpl_tab_num_args(dca) < 2)
+      {  xprintf("csv_driver: file name not specified\n");
+         longjmp(csv->jump, 0);
+      }
+      csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
+      strcpy(csv->fname, mpl_tab_get_arg(dca, 2));
+      if (mode == 'R')
+      {  /* open the file for reading */
+         int k;
+         csv->fp = fopen(csv->fname, "r");
+         if (csv->fp == NULL)
+         {  xprintf("csv_driver: unable to open %s - %s\n",
+               csv->fname, strerror(errno));
+            longjmp(csv->jump, 0);
+         }
+#if 1 /* 01/VI-2010 */
+         csv->nskip = 0;
+#endif
+         /* skip fake new-line */
+         read_field(csv);
+         xassert(csv->what == CSV_EOR);
+         /* read field names */
+         xassert(csv->nf == 0);
+         for (;;)
+         {  read_field(csv);
+            if (csv->what == CSV_EOR)
+               break;
+            if (csv->what != CSV_STR)
+            {  xprintf("%s:%d: invalid field name\n", csv->fname,
+                  csv->count);
+               longjmp(csv->jump, 0);
+            }
+            if (csv->nf == CSV_FIELD_MAX)
+            {  xprintf("%s:%d: too many fields\n", csv->fname,
+                  csv->count);
+               longjmp(csv->jump, 0);
+            }
+            csv->nf++;
+            /* find corresponding field in the table statement */
+            for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+            {  if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0)
+                  break;
+            }
+            csv->ref[csv->nf] = k;
+         }
+         /* find dummy RECNO field in the table statement */
+         for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+            if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
+         csv->ref[0] = k;
+      }
+      else if (mode == 'W')
+      {  /* open the file for writing */
+         int k, nf;
+         csv->fp = fopen(csv->fname, "w");
+         if (csv->fp == NULL)
+         {  xprintf("csv_driver: unable to create %s - %s\n",
+               csv->fname, strerror(errno));
+            longjmp(csv->jump, 0);
+         }
+         /* write field names */
+         nf = mpl_tab_num_flds(dca);
+         for (k = 1; k <= nf; k++)
+            fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k),
+               k < nf ? ',' : '\n');
+         csv->count++;
+      }
+      else
+         xassert(mode != mode);
+      /* the file has been open */
+      return csv;
+fail: /* the file cannot be open */
+      if (csv->fname != NULL) xfree(csv->fname);
+      if (csv->fp != NULL) fclose(csv->fp);
+      xfree(csv);
+      return NULL;
+}
+
+static int csv_read_record(TABDCA *dca, struct csv *csv)
+{     /* read next record from csv data file */
+      int k, ret = 0;
+      xassert(csv->mode == 'R');
+      if (setjmp(csv->jump))
+      {  ret = 1;
+         goto done;
+      }
+      /* read dummy RECNO field */
+      if (csv->ref[0] > 0)
+#if 0 /* 01/VI-2010 */
+         mpl_tab_set_num(dca, csv->ref[0], csv->count-1);
+#else
+         mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1);
+#endif
+      /* read fields */
+      for (k = 1; k <= csv->nf; k++)
+      {  read_field(csv);
+         if (csv->what == CSV_EOF)
+         {  /* end-of-file reached */
+            xassert(k == 1);
+            ret = -1;
+            goto done;
+         }
+         else if (csv->what == CSV_EOR)
+         {  /* end-of-record reached */
+            int lack = csv->nf - k + 1;
+            if (lack == 1)
+               xprintf("%s:%d: one field missing\n", csv->fname,
+                  csv->count);
+            else
+               xprintf("%s:%d: %d fields missing\n", csv->fname,
+                  csv->count, lack);
+            longjmp(csv->jump, 0);
+         }
+         else if (csv->what == CSV_NUM)
+         {  /* floating-point number */
+            if (csv->ref[k] > 0)
+            {  double num;
+               xassert(str2num(csv->field, &num) == 0);
+               mpl_tab_set_num(dca, csv->ref[k], num);
+            }
+         }
+         else if (csv->what == CSV_STR)
+         {  /* character string */
+            if (csv->ref[k] > 0)
+               mpl_tab_set_str(dca, csv->ref[k], csv->field);
+         }
+         else
+            xassert(csv != csv);
+      }
+      /* now there must be NL */
+      read_field(csv);
+      xassert(csv->what != CSV_EOF);
+      if (csv->what != CSV_EOR)
+      {  xprintf("%s:%d: too many fields\n", csv->fname, csv->count);
+         longjmp(csv->jump, 0);
+      }
+done: return ret;
+}
+
+static int csv_write_record(TABDCA *dca, struct csv *csv)
+{     /* write next record to csv data file */
+      int k, nf, ret = 0;
+      const char *c;
+      xassert(csv->mode == 'W');
+      nf = mpl_tab_num_flds(dca);
+      for (k = 1; k <= nf; k++)
+      {  switch (mpl_tab_get_type(dca, k))
+         {  case 'N':
+               fprintf(csv->fp, "%.*g", DBL_DIG,
+                  mpl_tab_get_num(dca, k));
+               break;
+            case 'S':
+               fputc('"', csv->fp);
+               for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++)
+               {  if (*c == '"')
+                     fputc('"', csv->fp), fputc('"', csv->fp);
+                  else
+                     fputc(*c, csv->fp);
+               }
+               fputc('"', csv->fp);
+               break;
+            default:
+               xassert(dca != dca);
+         }
+         fputc(k < nf ? ',' : '\n', csv->fp);
+      }
+      csv->count++;
+      if (ferror(csv->fp))
+      {  xprintf("%s:%d: write error - %s\n", csv->fname, csv->count,
+            strerror(errno));
+         ret = 1;
+      }
+      return ret;
+}
+
+static int csv_close_file(TABDCA *dca, struct csv *csv)
+{     /* close csv data file */
+      int ret = 0;
+      xassert(dca == dca);
+      if (csv->mode == 'W')
+      {  fflush(csv->fp);
+         if (ferror(csv->fp))
+         {  xprintf("%s:%d: write error - %s\n", csv->fname,
+               csv->count, strerror(errno));
+            ret = 1;
+         }
+      }
+      xfree(csv->fname);
+      fclose(csv->fp);
+      xfree(csv);
+      return ret;
+}
+
+/**********************************************************************/
+
+#define DBF_FIELD_MAX 50
+/* maximal number of fields in record */
+
+#define DBF_FDLEN_MAX 100
+/* maximal field length */
+
+struct dbf
+{     /* xBASE data file */
+      int mode;
+      /* 'R' = reading; 'W' = writing */
+      char *fname;
+      /* name of xBASE file */
+      FILE *fp;
+      /* stream assigned to xBASE file */
+      jmp_buf jump;
+      /* address for non-local go to in case of error */
+      int offset;
+      /* offset of a byte to be read next */
+      int count;
+      /* record count */
+      int nf;
+      /* number of fields */
+      int ref[1+DBF_FIELD_MAX];
+      /* ref[k] = k', if k-th field of the csv file corresponds to
+         k'-th field in the table statement; if ref[k] = 0, k-th field
+         of the csv file is ignored */
+      int type[1+DBF_FIELD_MAX];
+      /* type[k] is type of k-th field */
+      int len[1+DBF_FIELD_MAX];
+      /* len[k] is length of k-th field */
+      int prec[1+DBF_FIELD_MAX];
+      /* prec[k] is precision of k-th field */
+};
+
+static int read_byte(struct dbf *dbf)
+{     /* read byte from xBASE data file */
+      int b;
+      b = fgetc(dbf->fp);
+      if (ferror(dbf->fp))
+      {  xprintf("%s:0x%X: read error - %s\n", dbf->fname,
+            dbf->offset, strerror(errno));
+         longjmp(dbf->jump, 0);
+      }
+      if (feof(dbf->fp))
+      {  xprintf("%s:0x%X: unexpected end of file\n", dbf->fname,
+            dbf->offset);
+         longjmp(dbf->jump, 0);
+      }
+      xassert(0x00 <= b && b <= 0xFF);
+      dbf->offset++;
+      return b;
+}
+
+static void read_header(TABDCA *dca, struct dbf *dbf)
+{     /* read xBASE data file header */
+      int b, j, k, recl;
+      char name[10+1];
+      /* (ignored) */
+      for (j = 1; j <= 10; j++)
+         read_byte(dbf);
+      /* length of each record, in bytes */
+      recl = read_byte(dbf);
+      recl += read_byte(dbf) << 8;
+      /* (ignored) */
+      for (j = 1; j <= 20; j++)
+         read_byte(dbf);
+      /* field descriptor array */
+      xassert(dbf->nf == 0);
+      for (;;)
+      {  /* check for end of array */
+         b = read_byte(dbf);
+         if (b == 0x0D) break;
+         if (dbf->nf == DBF_FIELD_MAX)
+         {  xprintf("%s:0x%X: too many fields\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         dbf->nf++;
+         /* field name */
+         name[0] = (char)b;
+         for (j = 1; j < 10; j++)
+         {  b = read_byte(dbf);
+            name[j] = (char)b;
+         }
+         name[10] = '\0';
+         b = read_byte(dbf);
+         if (b != 0x00)
+         {  xprintf("%s:0x%X: invalid field name\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         /* find corresponding field in the table statement */
+         for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+            if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break;
+         dbf->ref[dbf->nf] = k;
+         /* field type */
+         b = read_byte(dbf);
+         if (!(b == 'C' || b == 'N'))
+         {  xprintf("%s:0x%X: invalid field type\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         dbf->type[dbf->nf] = b;
+         /* (ignored) */
+         for (j = 1; j <= 4; j++)
+            read_byte(dbf);
+         /* field length */
+         b = read_byte(dbf);
+         if (b == 0)
+         {  xprintf("%s:0x%X: invalid field length\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         if (b > DBF_FDLEN_MAX)
+         {  xprintf("%s:0x%X: field too long\n", dbf->fname,
+               dbf->offset);
+            longjmp(dbf->jump, 0);
+         }
+         dbf->len[dbf->nf] = b;
+         recl -= b;
+         /* (ignored) */
+         for (j = 1; j <= 15; j++)
+            read_byte(dbf);
+      }
+      if (recl != 1)
+      {  xprintf("%s:0x%X: invalid file header\n", dbf->fname,
+            dbf->offset);
+         longjmp(dbf->jump, 0);
+      }
+      /* find dummy RECNO field in the table statement */
+      for (k = mpl_tab_num_flds(dca); k >= 1; k--)
+         if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break;
+      dbf->ref[0] = k;
+      return;
+}
+
+static void parse_third_arg(TABDCA *dca, struct dbf *dbf)
+{     /* parse xBASE file format (third argument) */
+      int j, k, temp;
+      const char *arg;
+      dbf->nf = mpl_tab_num_flds(dca);
+      arg = mpl_tab_get_arg(dca, 3), j = 0;
+      for (k = 1; k <= dbf->nf; k++)
+      {  /* parse specification of k-th field */
+         if (arg[j] == '\0')
+         {  xprintf("xBASE driver: field %s: specification missing\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         /* parse field type */
+         if (arg[j] == 'C' || arg[j] == 'N')
+            dbf->type[k] = arg[j], j++;
+         else
+         {  xprintf("xBASE driver: field %s: invalid field type\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         /* check for left parenthesis */
+         if (arg[j] == '(')
+            j++;
+         else
+err:     {  xprintf("xBASE driver: field %s: invalid field format\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         /* parse field length */
+         temp = 0;
+         while (isdigit(arg[j]))
+         {  if (temp > DBF_FDLEN_MAX) break;
+            temp = 10 * temp + (arg[j] - '0'), j++;
+         }
+         if (!(1 <= temp && temp <= DBF_FDLEN_MAX))
+         {  xprintf("xBASE driver: field %s: invalid field length\n",
+               mpl_tab_get_name(dca, k));
+            longjmp(dbf->jump, 0);
+         }
+         dbf->len[k] = temp;
+         /* parse optional field precision */
+         if (dbf->type[k] == 'N' && arg[j] == ',')
+         {  j++;
+            temp = 0;
+            while (isdigit(arg[j]))
+            {  if (temp > dbf->len[k]) break;
+               temp = 10 * temp + (arg[j] - '0'), j++;
+            }
+            if (temp > dbf->len[k])
+            {  xprintf("xBASE driver: field %s: invalid field precision"
+                  "\n", mpl_tab_get_name(dca, k));
+               longjmp(dbf->jump, 0);
+            }
+            dbf->prec[k] = temp;
+         }
+         else
+            dbf->prec[k] = 0;
+         /* check for right parenthesis */
+         if (arg[j] == ')')
+            j++;
+         else
+            goto err;
+      }
+      /* ignore other specifications */
+      return;
+}
+
+static void write_byte(struct dbf *dbf, int b)
+{     /* write byte to xBASE data file */
+      fputc(b, dbf->fp);
+      dbf->offset++;
+      return;
+}
+
+static void write_header(TABDCA *dca, struct dbf *dbf)
+{     /* write xBASE data file header */
+      int j, k, temp;
+      const char *name;
+      /* version number */
+      write_byte(dbf, 0x03 /* file without DBT */);
+      /* date of last update (YYMMDD) */
+      write_byte(dbf, 70 /* 1970 */);
+      write_byte(dbf, 1 /* January */);
+      write_byte(dbf, 1 /* 1st */);
+      /* number of records (unknown so far) */
+      for (j = 1; j <= 4; j++)
+         write_byte(dbf, 0xFF);
+      /* length of the header, in bytes */
+      temp = 32 + dbf->nf * 32 + 1;
+      write_byte(dbf, temp);
+      write_byte(dbf, temp >> 8);
+      /* length of each record, in bytes */
+      temp = 1;
+      for (k = 1; k <= dbf->nf; k++)
+         temp += dbf->len[k];
+      write_byte(dbf, temp);
+      write_byte(dbf, temp >> 8);
+      /* (reserved) */
+      for (j = 1; j <= 20; j++)
+         write_byte(dbf, 0x00);
+      /* field descriptor array */
+      for (k = 1; k <= dbf->nf; k++)
+      {  /* field name (terminated by 0x00) */
+         name = mpl_tab_get_name(dca, k);
+         for (j = 0; j < 10 && name[j] != '\0'; j++)
+            write_byte(dbf, name[j]);
+         for (j = j; j < 11; j++)
+            write_byte(dbf, 0x00);
+         /* field type */
+         write_byte(dbf, dbf->type[k]);
+         /* (reserved) */
+         for (j = 1; j <= 4; j++)
+            write_byte(dbf, 0x00);
+         /* field length */
+         write_byte(dbf, dbf->len[k]);
+         /* field precision */
+         write_byte(dbf, dbf->prec[k]);
+         /* (reserved) */
+         for (j = 1; j <= 14; j++)
+            write_byte(dbf, 0x00);
+      }
+      /* end of header */
+      write_byte(dbf, 0x0D);
+      return;
+}
+
+static struct dbf *dbf_open_file(TABDCA *dca, int mode)
+{     /* open xBASE data file */
+      struct dbf *dbf;
+      /* create control structure */
+      dbf = xmalloc(sizeof(struct dbf));
+      dbf->mode = mode;
+      dbf->fname = NULL;
+      dbf->fp = NULL;
+      if (setjmp(dbf->jump)) goto fail;
+      dbf->offset = 0;
+      dbf->count = 0;
+      dbf->nf = 0;
+      /* try to open the xBASE data file */
+      if (mpl_tab_num_args(dca) < 2)
+      {  xprintf("xBASE driver: file name not specified\n");
+         longjmp(dbf->jump, 0);
+      }
+      dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1);
+      strcpy(dbf->fname, mpl_tab_get_arg(dca, 2));
+      if (mode == 'R')
+      {  /* open the file for reading */
+         dbf->fp = fopen(dbf->fname, "rb");
+         if (dbf->fp == NULL)
+         {  xprintf("xBASE driver: unable to open %s - %s\n",
+               dbf->fname, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+         read_header(dca, dbf);
+      }
+      else if (mode == 'W')
+      {  /* open the file for writing */
+         if (mpl_tab_num_args(dca) < 3)
+         {  xprintf("xBASE driver: file format not specified\n");
+            longjmp(dbf->jump, 0);
+         }
+         parse_third_arg(dca, dbf);
+         dbf->fp = fopen(dbf->fname, "wb");
+         if (dbf->fp == NULL)
+         {  xprintf("xBASE driver: unable to create %s - %s\n",
+               dbf->fname, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+         write_header(dca, dbf);
+      }
+      else
+         xassert(mode != mode);
+      /* the file has been open */
+      return dbf;
+fail: /* the file cannot be open */
+      if (dbf->fname != NULL) xfree(dbf->fname);
+      if (dbf->fp != NULL) fclose(dbf->fp);
+      xfree(dbf);
+      return NULL;
+}
+
+static int dbf_read_record(TABDCA *dca, struct dbf *dbf)
+{     /* read next record from xBASE data file */
+      int b, j, k, ret = 0;
+      char buf[DBF_FDLEN_MAX+1];
+      xassert(dbf->mode == 'R');
+      if (setjmp(dbf->jump))
+      {  ret = 1;
+         goto done;
+      }
+      /* check record flag */
+      b = read_byte(dbf);
+      if (b == 0x1A)
+      {  /* end of data */
+         ret = -1;
+         goto done;
+      }
+      if (b != 0x20)
+      {  xprintf("%s:0x%X: invalid record flag\n", dbf->fname,
+            dbf->offset);
+         longjmp(dbf->jump, 0);
+      }
+      /* read dummy RECNO field */
+      if (dbf->ref[0] > 0)
+         mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1);
+      /* read fields */
+      for (k = 1; k <= dbf->nf; k++)
+      {  /* read k-th field */
+         for (j = 0; j < dbf->len[k]; j++)
+            buf[j] = (char)read_byte(dbf);
+         buf[dbf->len[k]] = '\0';
+         /* set field value */
+         if (dbf->type[k] == 'C')
+         {  /* character field */
+            if (dbf->ref[k] > 0)
+               mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf));
+         }
+         else if (dbf->type[k] == 'N')
+         {  /* numeric field */
+            if (dbf->ref[k] > 0)
+            {  double num;
+               strspx(buf);
+               xassert(str2num(buf, &num) == 0);
+               mpl_tab_set_num(dca, dbf->ref[k], num);
+            }
+         }
+         else
+            xassert(dbf != dbf);
+      }
+      /* increase record count */
+      dbf->count++;
+done: return ret;
+}
+
+static int dbf_write_record(TABDCA *dca, struct dbf *dbf)
+{     /* write next record to xBASE data file */
+      int j, k, ret = 0;
+      char buf[255+1];
+      xassert(dbf->mode == 'W');
+      if (setjmp(dbf->jump))
+      {  ret = 1;
+         goto done;
+      }
+      /* record flag */
+      write_byte(dbf, 0x20);
+      xassert(dbf->nf == mpl_tab_num_flds(dca));
+      for (k = 1; k <= dbf->nf; k++)
+      {  if (dbf->type[k] == 'C')
+         {  /* character field */
+            const char *str;
+            if (mpl_tab_get_type(dca, k) == 'N')
+            {  sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+               str = buf;
+            }
+            else if (mpl_tab_get_type(dca, k) == 'S')
+               str = mpl_tab_get_str(dca, k);
+            else
+               xassert(dca != dca);
+            if ((int)strlen(str) > dbf->len[k])
+            {  xprintf("xBASE driver: field %s: cannot convert %.15s..."
+                  " to field format\n", mpl_tab_get_name(dca, k), str);
+               longjmp(dbf->jump, 0);
+            }
+            for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++)
+                write_byte(dbf, str[j]);
+            for (j = j; j < dbf->len[k]; j++)
+                write_byte(dbf, ' ');
+         }
+         else if (dbf->type[k] == 'N')
+         {  /* numeric field */
+            double num = mpl_tab_get_num(dca, k);
+            if (fabs(num) > 1e20)
+err:        {  xprintf("xBASE driver: field %s: cannot convert %g to fi"
+                  "eld format\n", mpl_tab_get_name(dca, k), num);
+               longjmp(dbf->jump, 0);
+            }
+            sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num);
+            xassert(strlen(buf) < sizeof(buf));
+            if ((int)strlen(buf) != dbf->len[k]) goto err;
+            for (j = 0; j < dbf->len[k]; j++)
+               write_byte(dbf, buf[j]);
+         }
+         else
+            xassert(dbf != dbf);
+      }
+      /* increase record count */
+      dbf->count++;
+done: return ret;
+}
+
+static int dbf_close_file(TABDCA *dca, struct dbf *dbf)
+{     /* close xBASE data file */
+      int ret = 0;
+      xassert(dca == dca);
+      if (dbf->mode == 'W')
+      {  if (setjmp(dbf->jump))
+         {  ret = 1;
+            goto skip;
+         }
+         /* end-of-file flag */
+         write_byte(dbf, 0x1A);
+         /* number of records */
+         dbf->offset = 4;
+         if (fseek(dbf->fp, dbf->offset, SEEK_SET))
+         {  xprintf("%s:0x%X: seek error - %s\n", dbf->fname,
+               dbf->offset, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+         write_byte(dbf, dbf->count);
+         write_byte(dbf, dbf->count >> 8);
+         write_byte(dbf, dbf->count >> 16);
+         write_byte(dbf, dbf->count >> 24);
+         fflush(dbf->fp);
+         if (ferror(dbf->fp))
+         {  xprintf("%s:0x%X: write error - %s\n", dbf->fname,
+               dbf->offset, strerror(errno));
+            longjmp(dbf->jump, 0);
+         }
+skip:    ;
+      }
+      xfree(dbf->fname);
+      fclose(dbf->fp);
+      xfree(dbf);
+      return ret;
+}
+
+/**********************************************************************/
+
+#define TAB_CSV   1
+#define TAB_XBASE 2
+#define TAB_ODBC  3
+#define TAB_MYSQL 4
+
+void mpl_tab_drv_open(MPL *mpl, int mode)
+{     TABDCA *dca = mpl->dca;
+      xassert(dca->id == 0);
+      xassert(dca->link == NULL);
+      xassert(dca->na >= 1);
+      if (strcmp(dca->arg[1], "CSV") == 0)
+      {  dca->id = TAB_CSV;
+         dca->link = csv_open_file(dca, mode);
+      }
+      else if (strcmp(dca->arg[1], "xBASE") == 0)
+      {  dca->id = TAB_XBASE;
+         dca->link = dbf_open_file(dca, mode);
+      }
+      else if (strcmp(dca->arg[1], "ODBC") == 0 ||
+               strcmp(dca->arg[1], "iODBC") == 0)
+      {  dca->id = TAB_ODBC;
+         dca->link = db_iodbc_open(dca, mode);
+      }
+      else if (strcmp(dca->arg[1], "MySQL") == 0)
+      {  dca->id = TAB_MYSQL;
+         dca->link = db_mysql_open(dca, mode);
+      }
+      else
+         xprintf("Invalid table driver `%s'\n", dca->arg[1]);
+      if (dca->link == NULL)
+         error(mpl, "error on opening table %s",
+            mpl->stmt->u.tab->name);
+      return;
+}
+
+int mpl_tab_drv_read(MPL *mpl)
+{     TABDCA *dca = mpl->dca;
+      int ret;
+      switch (dca->id)
+      {  case TAB_CSV:
+            ret = csv_read_record(dca, dca->link);
+            break;
+         case TAB_XBASE:
+            ret = dbf_read_record(dca, dca->link);
+            break;
+         case TAB_ODBC:
+            ret = db_iodbc_read(dca, dca->link);
+            break;
+         case TAB_MYSQL:
+            ret = db_mysql_read(dca, dca->link);
+            break;
+         default:
+            xassert(dca != dca);
+      }
+      if (ret > 0)
+         error(mpl, "error on reading data from table %s",
+            mpl->stmt->u.tab->name);
+      return ret;
+}
+
+void mpl_tab_drv_write(MPL *mpl)
+{     TABDCA *dca = mpl->dca;
+      int ret;
+      switch (dca->id)
+      {  case TAB_CSV:
+            ret = csv_write_record(dca, dca->link);
+            break;
+         case TAB_XBASE:
+            ret = dbf_write_record(dca, dca->link);
+            break;
+         case TAB_ODBC:
+            ret = db_iodbc_write(dca, dca->link);
+            break;
+         case TAB_MYSQL:
+            ret = db_mysql_write(dca, dca->link);
+            break;
+         default:
+            xassert(dca != dca);
+      }
+      if (ret)
+         error(mpl, "error on writing data to table %s",
+            mpl->stmt->u.tab->name);
+      return;
+}
+
+void mpl_tab_drv_close(MPL *mpl)
+{     TABDCA *dca = mpl->dca;
+      int ret;
+      switch (dca->id)
+      {  case TAB_CSV:
+            ret = csv_close_file(dca, dca->link);
+            break;
+         case TAB_XBASE:
+            ret = dbf_close_file(dca, dca->link);
+            break;
+         case TAB_ODBC:
+            ret = db_iodbc_close(dca, dca->link);
+            break;
+         case TAB_MYSQL:
+            ret = db_mysql_close(dca, dca->link);
+            break;
+         default:
+            xassert(dca != dca);
+      }
+      dca->id = 0;
+      dca->link = NULL;
+      if (ret)
+         error(mpl, "error on closing table %s",
+            mpl->stmt->u.tab->name);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpmps.c
===================================================================
--- deps/glpk/src/glpmps.c	(revision 9)
+++ deps/glpk/src/glpmps.c	(revision 9)
@@ -0,0 +1,1401 @@
+/* glpmps.c (MPS format routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_mpscp - initialize MPS format control parameters
+*
+*  SYNOPSIS
+*
+*  void glp_init_mpscp(glp_mpscp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_mpscp initializes control parameters, which are
+*  used by the MPS input/output routines glp_read_mps and glp_write_mps,
+*  with default values.
+*
+*  Default values of the control parameters are stored in the glp_mpscp
+*  structure, which the parameter parm points to. */
+
+void glp_init_mpscp(glp_mpscp *parm)
+{     parm->blank = '\0';
+      parm->obj_name = NULL;
+      parm->tol_mps = 1e-12;
+      return;
+}
+
+static void check_parm(const char *func, const glp_mpscp *parm)
+{     /* check control parameters */
+      if (!(0x00 <= parm->blank && parm->blank <= 0xFF) ||
+          !(parm->blank == '\0' || isprint(parm->blank)))
+         xerror("%s: blank = 0x%02X; invalid parameter\n",
+            func, parm->blank);
+      if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255))
+         xerror("%s: obj_name = \"%.12s...\"; parameter too long\n",
+            func, parm->obj_name);
+      if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0))
+         xerror("%s: tol_mps = %g; invalid parameter\n",
+            func, parm->tol_mps);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_read_mps - read problem data in MPS format
+*
+*  SYNOPSIS
+*
+*  int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_read_mps reads problem data in MPS format from a
+*  text file.
+*
+*  The parameter fmt specifies the version of MPS format:
+*
+*  GLP_MPS_DECK - fixed (ancient) MPS format;
+*  GLP_MPS_FILE - free (modern) MPS format.
+*
+*  The parameter parm is a pointer to the structure glp_mpscp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  read.
+*
+*  Note that before reading data the current content of the problem
+*  object is completely erased with the routine glp_erase_prob.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_read_mps returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* pointer to problem object */
+      int deck;
+      /* MPS format (0 - free, 1 - fixed) */
+      const glp_mpscp *parm;
+      /* pointer to control parameters */
+      const char *fname;
+      /* name of input MPS file */
+      XFILE *fp;
+      /* stream assigned to input MPS file */
+      jmp_buf jump;
+      /* label for go to in case of error */
+      int recno;
+      /* current record (card) number */
+      int recpos;
+      /* current record (card) position */
+      int c;
+      /* current character */
+      int fldno;
+      /* current field number */
+      char field[255+1];
+      /* current field content */
+      int w80;
+      /* warning 'record must not be longer than 80 chars' issued */
+      int wef;
+      /* warning 'extra fields detected beyond field 6' issued */
+      int obj_row;
+      /* objective row number */
+      void *work1, *work2, *work3;
+      /* working arrays */
+};
+
+static void error(struct csa *csa, const char *fmt, ...)
+{     /* print error message and terminate processing */
+      va_list arg;
+      xprintf("%s:%d: ", csa->fname, csa->recno);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      longjmp(csa->jump, 1);
+      /* no return */
+}
+
+static void warning(struct csa *csa, const char *fmt, ...)
+{     /* print warning message and continue processing */
+      va_list arg;
+      xprintf("%s:%d: warning: ", csa->fname, csa->recno);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      return;
+}
+
+static void read_char(struct csa *csa)
+{     /* read next character */
+      int c;
+      if (csa->c == '\n')
+         csa->recno++, csa->recpos = 0;
+      csa->recpos++;
+read: c = xfgetc(csa->fp);
+      if (c < 0)
+      {  if (xferror(csa->fp))
+            error(csa, "read error - %s\n", xerrmsg());
+         else if (csa->c == '\n')
+            error(csa, "unexpected end of file\n");
+         else
+         {  warning(csa, "missing final end of line\n");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (csa->c == '\r')
+      {  c = '\r';
+         goto badc;
+      }
+      else if (csa->deck && c == '\r')
+      {  csa->c = '\r';
+         goto read;
+      }
+      else if (c == ' ')
+         ;
+      else if (isspace(c))
+      {  if (csa->deck)
+badc:       error(csa, "in fixed MPS format white-space character 0x%02"
+               "X is not allowed\n", c);
+         c = ' ';
+      }
+      else if (iscntrl(c))
+         error(csa, "invalid control character 0x%02X\n", c);
+      if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1)
+      {  warning(csa, "in fixed MPS format record must not be longer th"
+            "an 80 characters\n");
+         csa->w80++;
+      }
+      csa->c = c;
+      return;
+}
+
+static int indicator(struct csa *csa, int name)
+{     /* skip comment records and read possible indicator record */
+      int ret;
+      /* reset current field number */
+      csa->fldno = 0;
+loop: /* read the very first character of the next record */
+      xassert(csa->c == '\n');
+      read_char(csa);
+      if (csa->c == ' ' || csa->c == '\n')
+      {  /* data record */
+         ret = 0;
+      }
+      else if (csa->c == '*')
+      {  /* comment record */
+         while (csa->c != '\n')
+            read_char(csa);
+         goto loop;
+      }
+      else
+      {  /* indicator record */
+         int len = 0;
+         while (csa->c != ' ' && csa->c != '\n' && len < 12)
+         {  csa->field[len++] = (char)csa->c;
+            read_char(csa);
+         }
+         csa->field[len] = '\0';
+         if (!(strcmp(csa->field, "NAME")    == 0 ||
+               strcmp(csa->field, "ROWS")    == 0 ||
+               strcmp(csa->field, "COLUMNS") == 0 ||
+               strcmp(csa->field, "RHS")     == 0 ||
+               strcmp(csa->field, "RANGES")  == 0 ||
+               strcmp(csa->field, "BOUNDS")  == 0 ||
+               strcmp(csa->field, "ENDATA")  == 0))
+            error(csa, "invalid indicator record\n");
+         if (!name)
+         {  while (csa->c != '\n')
+               read_char(csa);
+         }
+         ret = 1;
+      }
+      return ret;
+}
+
+static void read_field(struct csa *csa)
+{     /* read next field of the current data record */
+      csa->fldno++;
+      if (csa->deck)
+      {  /* fixed MPS format */
+         int beg, end, pos;
+         /* determine predefined field positions */
+         if (csa->fldno == 1)
+            beg = 2, end = 3;
+         else if (csa->fldno == 2)
+            beg = 5, end = 12;
+         else if (csa->fldno == 3)
+            beg = 15, end = 22;
+         else if (csa->fldno == 4)
+            beg = 25, end = 36;
+         else if (csa->fldno == 5)
+            beg = 40, end = 47;
+         else if (csa->fldno == 6)
+            beg = 50, end = 61;
+         else
+            xassert(csa != csa);
+         /* skip blanks preceding the current field */
+         if (csa->c != '\n')
+         {  pos = csa->recpos;
+            while (csa->recpos < beg)
+            {  if (csa->c == ' ')
+                  ;
+               else if (csa->c == '\n')
+                  break;
+               else
+                  error(csa, "in fixed MPS format positions %d-%d must "
+                     "be blank\n", pos, beg-1);
+               read_char(csa);
+            }
+         }
+         /* skip possible comment beginning in the field 3 or 5 */
+         if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$')
+         {  while (csa->c != '\n')
+               read_char(csa);
+         }
+         /* read the current field */
+         for (pos = beg; pos <= end; pos++)
+         {  if (csa->c == '\n') break;
+            csa->field[pos-beg] = (char)csa->c;
+            read_char(csa);
+         }
+         csa->field[pos-beg] = '\0';
+         strtrim(csa->field);
+         /* skip blanks following the last field */
+         if (csa->fldno == 6 && csa->c != '\n')
+         {  while (csa->recpos <= 72)
+            {  if (csa->c == ' ')
+                  ;
+               else if (csa->c == '\n')
+                  break;
+               else
+                  error(csa, "in fixed MPS format positions 62-72 must "
+                     "be blank\n");
+               read_char(csa);
+            }
+            while (csa->c != '\n')
+               read_char(csa);
+         }
+      }
+      else
+      {  /* free MPS format */
+         int len;
+         /* skip blanks preceding the current field */
+         while (csa->c == ' ')
+            read_char(csa);
+         /* skip possible comment */
+         if (csa->c == '$')
+         {  while (csa->c != '\n')
+               read_char(csa);
+         }
+         /* read the current field */
+         len = 0;
+         while (!(csa->c == ' ' || csa->c == '\n'))
+         {  if (len == 255)
+               error(csa, "length of field %d exceeds 255 characters\n",
+                  csa->fldno++);
+            csa->field[len++] = (char)csa->c;
+            read_char(csa);
+         }
+         csa->field[len] = '\0';
+         /* skip anything following the last field (any extra fields
+            are considered to be comments) */
+         if (csa->fldno == 6)
+         {  while (csa->c == ' ')
+               read_char(csa);
+            if (csa->c != '$' && csa->c != '\n' && csa->wef < 1)
+            {  warning(csa, "some extra field(s) detected beyond field "
+                  "6; field(s) ignored\n");
+               csa->wef++;
+            }
+            while (csa->c != '\n')
+               read_char(csa);
+         }
+      }
+      return;
+}
+
+static void patch_name(struct csa *csa, char *name)
+{     /* process embedded blanks in symbolic name */
+      int blank = csa->parm->blank;
+      if (blank == '\0')
+      {  /* remove emedded blanks */
+         strspx(name);
+      }
+      else
+      {  /* replace embedded blanks by specified character */
+         for (; *name != '\0'; name++)
+            if (*name == ' ') *name = (char)blank;
+      }
+      return;
+}
+
+static double read_number(struct csa *csa)
+{     /* read next field and convert it to floating-point number */
+      double x;
+      char *s;
+      /* read next field */
+      read_field(csa);
+      xassert(csa->fldno == 4 || csa->fldno == 6);
+      if (csa->field[0] == '\0')
+         error(csa, "missing numeric value in field %d\n", csa->fldno);
+      /* skip initial spaces of the field */
+      for (s = csa->field; *s == ' '; s++);
+      /* perform conversion */
+      if (str2num(s, &x) != 0)
+         error(csa, "cannot convert `%s' to floating-point number\n",
+            s);
+      return x;
+}
+
+static void skip_field(struct csa *csa)
+{     /* read and skip next field (assumed to be blank) */
+      read_field(csa);
+      if (csa->field[0] != '\0')
+         error(csa, "field %d must be blank\n", csa->fldno);
+      return;
+}
+
+static void read_name(struct csa *csa)
+{     /* read NAME indicator record */
+      if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0))
+         error(csa, "missing NAME indicator record\n");
+      /* this indicator record looks like a data record; simulate that
+         fields 1 and 2 were read */
+      csa->fldno = 2;
+      /* field 3: model name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+         warning(csa, "missing model name in field 3\n");
+      else
+         glp_set_prob_name(csa->P, csa->field);
+      /* skip anything following field 3 */
+      while (csa->c != '\n')
+         read_char(csa);
+      return;
+}
+
+static void read_rows(struct csa *csa)
+{     /* read ROWS section */
+      int i, type;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1: row type */
+      read_field(csa), strspx(csa->field);
+      if (strcmp(csa->field, "N") == 0)
+         type = GLP_FR;
+      else if (strcmp(csa->field, "G") == 0)
+         type = GLP_LO;
+      else if (strcmp(csa->field, "L") == 0)
+         type = GLP_UP;
+      else if (strcmp(csa->field, "E") == 0)
+         type = GLP_FX;
+      else if (csa->field[0] == '\0')
+         error(csa, "missing row type in field 1\n");
+      else
+         error(csa, "invalid row type in field 1\n");
+      /* field 2: row name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+         error(csa, "missing row name in field 2\n");
+      if (glp_find_row(csa->P, csa->field) != 0)
+         error(csa, "row `%s' multiply specified\n", csa->field);
+      i = glp_add_rows(csa->P, 1);
+      glp_set_row_name(csa->P, i, csa->field);
+      glp_set_row_bnds(csa->P, i, type, 0.0, 0.0);
+      /* fields 3, 4, 5, and 6 must be blank */
+      skip_field(csa);
+      skip_field(csa);
+      skip_field(csa);
+      skip_field(csa);
+      goto loop;
+done: return;
+}
+
+static void read_columns(struct csa *csa)
+{     /* read COLUMNS section */
+      int i, j, f, len, kind = GLP_CV, *ind;
+      double aij, *val;
+      char name[255+1], *flag;
+      /* allocate working arrays */
+      csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int));
+      csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double));
+      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+      memset(&flag[1], 0, csa->P->m);
+      /* no current column exists */
+      j = 0, len = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1 must be blank */
+      if (csa->deck)
+      {  read_field(csa);
+         if (csa->field[0] != '\0')
+            error(csa, "field 1 must be blank\n");
+      }
+      else
+         csa->fldno++;
+      /* field 2: column or kind name */
+      read_field(csa), patch_name(csa, csa->field);
+      strcpy(name, csa->field);
+      /* field 3: row name or keyword 'MARKER' */
+      read_field(csa), patch_name(csa, csa->field);
+      if (strcmp(csa->field, "'MARKER'") == 0)
+      {  /* process kind data record */
+         /* field 4 must be blank */
+         if (csa->deck)
+         {  read_field(csa);
+            if (csa->field[0] != '\0')
+               error(csa, "field 4 must be blank\n");
+         }
+         else
+            csa->fldno++;
+         /* field 5: keyword 'INTORG' or 'INTEND' */
+         read_field(csa), patch_name(csa, csa->field);
+         if (strcmp(csa->field, "'INTORG'") == 0)
+            kind = GLP_IV;
+         else if (strcmp(csa->field, "'INTEND'") == 0)
+            kind = GLP_CV;
+         else if (csa->field[0] == '\0')
+            error(csa, "missing keyword in field 5\n");
+         else
+            error(csa, "invalid keyword in field 5\n");
+         /* field 6 must be blank */
+         skip_field(csa);
+         goto loop;
+      }
+      /* process column name specified in field 2 */
+      if (name[0] == '\0')
+      {  /* the same column as in previous data record */
+         if (j == 0)
+            error(csa, "missing column name in field 2\n");
+      }
+      else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0)
+      {  /* the same column as in previous data record */
+         xassert(j != 0);
+      }
+      else
+      {  /* store the current column */
+         if (j != 0)
+         {  glp_set_mat_col(csa->P, j, len, ind, val);
+            while (len > 0) flag[ind[len--]] = 0;
+         }
+         /* create new column */
+         if (glp_find_col(csa->P, name) != 0)
+            error(csa, "column `%s' multiply specified\n", name);
+         j = glp_add_cols(csa->P, 1);
+         glp_set_col_name(csa->P, j, name);
+         glp_set_col_kind(csa->P, j, kind);
+         if (kind == GLP_CV)
+            glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0);
+         else if (kind == GLP_IV)
+            glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0);
+         else
+            xassert(kind != kind);
+      }
+      /* process fields 3-4 and 5-6 */
+      for (f = 3; f <= 5; f += 2)
+      {  /* field 3 or 5: row name */
+         if (f == 3)
+         {  if (csa->field[0] == '\0')
+               error(csa, "missing row name in field 3\n");
+         }
+         else
+         {  read_field(csa), patch_name(csa, csa->field);
+            if (csa->field[0] == '\0')
+            {  /* if field 5 is blank, field 6 also must be blank */
+               skip_field(csa);
+               continue;
+            }
+         }
+         i = glp_find_row(csa->P, csa->field);
+         if (i == 0)
+            error(csa, "row `%s' not found\n", csa->field);
+         if (flag[i])
+            error(csa, "duplicate coefficient in row `%s'\n",
+               csa->field);
+         /* field 4 or 6: coefficient value */
+         aij = read_number(csa);
+         if (fabs(aij) < csa->parm->tol_mps) aij = 0.0;
+         len++, ind[len] = i, val[len] = aij, flag[i] = 1;
+      }
+      goto loop;
+done: /* store the last column */
+      if (j != 0)
+         glp_set_mat_col(csa->P, j, len, ind, val);
+      /* free working arrays */
+      xfree(ind);
+      xfree(val);
+      xfree(flag);
+      csa->work1 = csa->work2 = csa->work3 = NULL;
+      return;
+}
+
+static void read_rhs(struct csa *csa)
+{     /* read RHS section */
+      int i, f, v, type;
+      double rhs;
+      char name[255+1], *flag;
+      /* allocate working array */
+      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+      memset(&flag[1], 0, csa->P->m);
+      /* no current RHS vector exists */
+      v = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1 must be blank */
+      if (csa->deck)
+      {  read_field(csa);
+         if (csa->field[0] != '\0')
+            error(csa, "field 1 must be blank\n");
+      }
+      else
+         csa->fldno++;
+      /* field 2: RHS vector name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+      {  /* the same RHS vector as in previous data record */
+         if (v == 0)
+         {  warning(csa, "missing RHS vector name in field 2\n");
+            goto blnk;
+         }
+      }
+      else if (v != 0 && strcmp(csa->field, name) == 0)
+      {  /* the same RHS vector as in previous data record */
+         xassert(v != 0);
+      }
+      else
+blnk: {  /* new RHS vector */
+         if (v != 0)
+            error(csa, "multiple RHS vectors not supported\n");
+         v++;
+         strcpy(name, csa->field);
+      }
+      /* process fields 3-4 and 5-6 */
+      for (f = 3; f <= 5; f += 2)
+      {  /* field 3 or 5: row name */
+         read_field(csa), patch_name(csa, csa->field);
+         if (csa->field[0] == '\0')
+         {  if (f == 3)
+               error(csa, "missing row name in field 3\n");
+            else
+            {  /* if field 5 is blank, field 6 also must be blank */
+               skip_field(csa);
+               continue;
+            }
+         }
+         i = glp_find_row(csa->P, csa->field);
+         if (i == 0)
+            error(csa, "row `%s' not found\n", csa->field);
+         if (flag[i])
+            error(csa, "duplicate right-hand side for row `%s'\n",
+               csa->field);
+         /* field 4 or 6: right-hand side value */
+         rhs = read_number(csa);
+         if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0;
+         type = csa->P->row[i]->type;
+         if (type == GLP_FR)
+         {  if (i == csa->obj_row)
+               glp_set_obj_coef(csa->P, 0, rhs);
+            else if (rhs != 0.0)
+               warning(csa, "non-zero right-hand side for free row `%s'"
+                  " ignored\n", csa->P->row[i]->name);
+         }
+         else
+            glp_set_row_bnds(csa->P, i, type, rhs, rhs);
+         flag[i] = 1;
+      }
+      goto loop;
+done: /* free working array */
+      xfree(flag);
+      csa->work3 = NULL;
+      return;
+}
+
+static void read_ranges(struct csa *csa)
+{     /* read RANGES section */
+      int i, f, v, type;
+      double rhs, rng;
+      char name[255+1], *flag;
+      /* allocate working array */
+      csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char));
+      memset(&flag[1], 0, csa->P->m);
+      /* no current RANGES vector exists */
+      v = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1 must be blank */
+      if (csa->deck)
+      {  read_field(csa);
+         if (csa->field[0] != '\0')
+            error(csa, "field 1 must be blank\n");
+      }
+      else
+         csa->fldno++;
+      /* field 2: RANGES vector name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+      {  /* the same RANGES vector as in previous data record */
+         if (v == 0)
+         {  warning(csa, "missing RANGES vector name in field 2\n");
+            goto blnk;
+         }
+      }
+      else if (v != 0 && strcmp(csa->field, name) == 0)
+      {  /* the same RANGES vector as in previous data record */
+         xassert(v != 0);
+      }
+      else
+blnk: {  /* new RANGES vector */
+         if (v != 0)
+            error(csa, "multiple RANGES vectors not supported\n");
+         v++;
+         strcpy(name, csa->field);
+      }
+      /* process fields 3-4 and 5-6 */
+      for (f = 3; f <= 5; f += 2)
+      {  /* field 3 or 5: row name */
+         read_field(csa), patch_name(csa, csa->field);
+         if (csa->field[0] == '\0')
+         {  if (f == 3)
+               error(csa, "missing row name in field 3\n");
+            else
+            {  /* if field 5 is blank, field 6 also must be blank */
+               skip_field(csa);
+               continue;
+            }
+         }
+         i = glp_find_row(csa->P, csa->field);
+         if (i == 0)
+            error(csa, "row `%s' not found\n", csa->field);
+         if (flag[i])
+            error(csa, "duplicate range for row `%s'\n", csa->field);
+         /* field 4 or 6: range value */
+         rng = read_number(csa);
+         if (fabs(rng) < csa->parm->tol_mps) rng = 0.0;
+         type = csa->P->row[i]->type;
+         if (type == GLP_FR)
+            warning(csa, "range for free row `%s' ignored\n",
+               csa->P->row[i]->name);
+         else if (type == GLP_LO)
+         {  rhs = csa->P->row[i]->lb;
+            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
+               rhs, rhs + fabs(rng));
+         }
+         else if (type == GLP_UP)
+         {  rhs = csa->P->row[i]->ub;
+            glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB,
+               rhs - fabs(rng), rhs);
+         }
+         else if (type == GLP_FX)
+         {  rhs = csa->P->row[i]->lb;
+            if (rng > 0.0)
+               glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng);
+            else if (rng < 0.0)
+               glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs);
+         }
+         else
+            xassert(type != type);
+         flag[i] = 1;
+      }
+      goto loop;
+done: /* free working array */
+      xfree(flag);
+      csa->work3 = NULL;
+      return;
+}
+
+static void read_bounds(struct csa *csa)
+{     /* read BOUNDS section */
+      GLPCOL *col;
+      int j, v, mask, data;
+      double bnd, lb, ub;
+      char type[2+1], name[255+1], *flag;
+      /* allocate working array */
+      csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char));
+      memset(&flag[1], 0, csa->P->n);
+      /* no current BOUNDS vector exists */
+      v = 0;
+loop: if (indicator(csa, 0)) goto done;
+      /* field 1: bound type */
+      read_field(csa);
+      if (strcmp(csa->field, "LO") == 0)
+         mask = 0x01, data = 1;
+      else if (strcmp(csa->field, "UP") == 0)
+         mask = 0x10, data = 1;
+      else if (strcmp(csa->field, "FX") == 0)
+         mask = 0x11, data = 1;
+      else if (strcmp(csa->field, "FR") == 0)
+         mask = 0x11, data = 0;
+      else if (strcmp(csa->field, "MI") == 0)
+         mask = 0x01, data = 0;
+      else if (strcmp(csa->field, "PL") == 0)
+         mask = 0x10, data = 0;
+      else if (strcmp(csa->field, "LI") == 0)
+         mask = 0x01, data = 1;
+      else if (strcmp(csa->field, "UI") == 0)
+         mask = 0x10, data = 1;
+      else if (strcmp(csa->field, "BV") == 0)
+         mask = 0x11, data = 0;
+      else if (csa->field[0] == '\0')
+         error(csa, "missing bound type in field 1\n");
+      else
+         error(csa, "invalid bound type in field 1\n");
+      strcpy(type, csa->field);
+      /* field 2: BOUNDS vector name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+      {  /* the same BOUNDS vector as in previous data record */
+         if (v == 0)
+         {  warning(csa, "missing BOUNDS vector name in field 2\n");
+            goto blnk;
+         }
+      }
+      else if (v != 0 && strcmp(csa->field, name) == 0)
+      {  /* the same BOUNDS vector as in previous data record */
+         xassert(v != 0);
+      }
+      else
+blnk: {  /* new BOUNDS vector */
+         if (v != 0)
+            error(csa, "multiple BOUNDS vectors not supported\n");
+         v++;
+         strcpy(name, csa->field);
+      }
+      /* field 3: column name */
+      read_field(csa), patch_name(csa, csa->field);
+      if (csa->field[0] == '\0')
+         error(csa, "missing column name in field 3\n");
+      j = glp_find_col(csa->P, csa->field);
+      if (j == 0)
+         error(csa, "column `%s' not found\n", csa->field);
+      if ((flag[j] & mask) == 0x01)
+         error(csa, "duplicate lower bound for column `%s'\n",
+            csa->field);
+      if ((flag[j] & mask) == 0x10)
+         error(csa, "duplicate upper bound for column `%s'\n",
+            csa->field);
+      xassert((flag[j] & mask) == 0x00);
+      /* field 4: bound value */
+      if (data)
+      {  bnd = read_number(csa);
+         if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0;
+      }
+      else
+         read_field(csa), bnd = 0.0;
+      /* get current column bounds */
+      col = csa->P->col[j];
+      if (col->type == GLP_FR)
+         lb = -DBL_MAX, ub = +DBL_MAX;
+      else if (col->type == GLP_LO)
+         lb = col->lb, ub = +DBL_MAX;
+      else if (col->type == GLP_UP)
+         lb = -DBL_MAX, ub = col->ub;
+      else if (col->type == GLP_DB)
+         lb = col->lb, ub = col->ub;
+      else if (col->type == GLP_FX)
+         lb = ub = col->lb;
+      else
+         xassert(col != col);
+      /* change column bounds */
+      if (strcmp(type, "LO") == 0)
+         lb = bnd;
+      else if (strcmp(type, "UP") == 0)
+         ub = bnd;
+      else if (strcmp(type, "FX") == 0)
+         lb = ub = bnd;
+      else if (strcmp(type, "FR") == 0)
+         lb = -DBL_MAX, ub = +DBL_MAX;
+      else if (strcmp(type, "MI") == 0)
+         lb = -DBL_MAX;
+      else if (strcmp(type, "PL") == 0)
+         ub = +DBL_MAX;
+      else if (strcmp(type, "LI") == 0)
+      {  glp_set_col_kind(csa->P, j, GLP_IV);
+         lb = ceil(bnd);
+      }
+      else if (strcmp(type, "UI") == 0)
+      {  glp_set_col_kind(csa->P, j, GLP_IV);
+         ub = floor(bnd);
+      }
+      else if (strcmp(type, "BV") == 0)
+      {  glp_set_col_kind(csa->P, j, GLP_IV);
+         lb = 0.0, ub = 1.0;
+      }
+      else
+         xassert(type != type);
+      /* set new column bounds */
+      if (lb == -DBL_MAX && ub == +DBL_MAX)
+         glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub);
+      else if (ub == +DBL_MAX)
+         glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub);
+      else if (lb == -DBL_MAX)
+         glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub);
+      else if (lb != ub)
+         glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub);
+      else
+         glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub);
+      flag[j] |= (char)mask;
+      /* fields 5 and 6 must be blank */
+      skip_field(csa);
+      skip_field(csa);
+      goto loop;
+done: /* free working array */
+      xfree(flag);
+      csa->work3 = NULL;
+      return;
+}
+
+int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname)
+{     /* read problem data in MPS format */
+      glp_mpscp _parm;
+      struct csa _csa, *csa = &_csa;
+      int ret;
+      xprintf("Reading problem data from `%s'...\n", fname);
+      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
+         xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt);
+      if (parm == NULL)
+         glp_init_mpscp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_read_mps", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->deck = (fmt == GLP_MPS_DECK);
+      csa->parm = parm;
+      csa->fname = fname;
+      csa->fp = NULL;
+      if (setjmp(csa->jump))
+      {  ret = 1;
+         goto done;
+      }
+      csa->recno = csa->recpos = 0;
+      csa->c = '\n';
+      csa->fldno = 0;
+      csa->field[0] = '\0';
+      csa->w80 = csa->wef = 0;
+      csa->obj_row = 0;
+      csa->work1 = csa->work2 = csa->work3 = NULL;
+      /* erase problem object */
+      glp_erase_prob(P);
+      glp_create_index(P);
+      /* open input MPS file */
+      csa->fp = xfopen(fname, "r");
+      if (csa->fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* read NAME indicator record */
+      read_name(csa);
+      if (P->name != NULL)
+         xprintf("Problem: %s\n", P->name);
+      /* read ROWS section */
+      if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0))
+         error(csa, "missing ROWS indicator record\n");
+      read_rows(csa);
+      /* determine objective row */
+      if (parm->obj_name == NULL || parm->obj_name[0] == '\0')
+      {  /* use the first row of N type */
+         int i;
+         for (i = 1; i <= P->m; i++)
+         {  if (P->row[i]->type == GLP_FR)
+            {  csa->obj_row = i;
+               break;
+            }
+         }
+         if (csa->obj_row == 0)
+            warning(csa, "unable to determine objective row\n");
+      }
+      else
+      {  /* use a row with specified name */
+         int i;
+         for (i = 1; i <= P->m; i++)
+         {  xassert(P->row[i]->name != NULL);
+            if (strcmp(parm->obj_name, P->row[i]->name) == 0)
+            {  csa->obj_row = i;
+               break;
+            }
+         }
+         if (csa->obj_row == 0)
+            error(csa, "objective row `%s' not found\n",
+               parm->obj_name);
+      }
+      if (csa->obj_row != 0)
+      {  glp_set_obj_name(P, P->row[csa->obj_row]->name);
+         xprintf("Objective: %s\n", P->obj);
+      }
+      /* read COLUMNS section */
+      if (strcmp(csa->field, "COLUMNS") != 0)
+         error(csa, "missing COLUMNS indicator record\n");
+      read_columns(csa);
+      /* set objective coefficients */
+      if (csa->obj_row != 0)
+      {  GLPAIJ *aij;
+         for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij =
+            aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val);
+      }
+      /* read optional RHS section */
+      if (strcmp(csa->field, "RHS") == 0)
+         read_rhs(csa);
+      /* read optional RANGES section */
+      if (strcmp(csa->field, "RANGES") == 0)
+         read_ranges(csa);
+      /* read optional BOUNDS section */
+      if (strcmp(csa->field, "BOUNDS") == 0)
+         read_bounds(csa);
+      /* read ENDATA indicator record */
+      if (strcmp(csa->field, "ENDATA") != 0)
+         error(csa, "invalid use of %s indicator record\n",
+            csa->field);
+      /* print some statistics */
+      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
+         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
+         P->nnz, P->nnz == 1 ? "" : "s");
+      if (glp_get_num_int(P) > 0)
+      {  int ni = glp_get_num_int(P);
+         int nb = glp_get_num_bin(P);
+         if (ni == 1)
+         {  if (nb == 0)
+               xprintf("One variable is integer\n");
+            else
+               xprintf("One variable is binary\n");
+         }
+         else
+         {  xprintf("%d integer variables, ", ni);
+            if (nb == 0)
+               xprintf("none");
+            else if (nb == 1)
+               xprintf("one");
+            else if (nb == ni)
+               xprintf("all");
+            else
+               xprintf("%d", nb);
+            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
+         }
+      }
+      xprintf("%d records were read\n", csa->recno);
+      /* problem data has been successfully read */
+      glp_delete_index(P);
+      glp_sort_matrix(P);
+      ret = 0;
+done: if (csa->fp != NULL) xfclose(csa->fp);
+      if (csa->work1 != NULL) xfree(csa->work1);
+      if (csa->work2 != NULL) xfree(csa->work2);
+      if (csa->work3 != NULL) xfree(csa->work3);
+      if (ret != 0) glp_erase_prob(P);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_write_mps - write problem data in MPS format
+*
+*  SYNOPSIS
+*
+*  int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+*     const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine glp_write_mps writes problem data in MPS format to a
+*  text file.
+*
+*  The parameter fmt specifies the version of MPS format:
+*
+*  GLP_MPS_DECK - fixed (ancient) MPS format;
+*  GLP_MPS_FILE - free (modern) MPS format.
+*
+*  The parameter parm is a pointer to the structure glp_mpscp, which
+*  specifies control parameters used by the routine. If parm is NULL,
+*  the routine uses default settings.
+*
+*  The character string fname specifies a name of the text file to be
+*  written.
+*
+*  RETURNS
+*
+*  If the operation was successful, the routine glp_read_mps returns
+*  zero. Otherwise, it prints an error message and returns non-zero. */
+
+#define csa csa1
+
+struct csa
+{     /* common storage area */
+      glp_prob *P;
+      /* pointer to problem object */
+      int deck;
+      /* MPS format (0 - free, 1 - fixed) */
+      const glp_mpscp *parm;
+      /* pointer to control parameters */
+      char field[255+1];
+      /* field buffer */
+};
+
+static char *mps_name(struct csa *csa)
+{     /* make problem name */
+      char *f;
+      if (csa->P->name == NULL)
+         csa->field[0] = '\0';
+      else if (csa->deck)
+      {  strncpy(csa->field, csa->P->name, 8);
+         csa->field[8] = '\0';
+      }
+      else
+         strcpy(csa->field, csa->P->name);
+      for (f = csa->field; *f != '\0'; f++)
+         if (*f == ' ') *f = '_';
+      return csa->field;
+}
+
+static char *row_name(struct csa *csa, int i)
+{     /* make i-th row name */
+      char *f;
+      xassert(0 <= i && i <= csa->P->m);
+      if (i == 0 || csa->P->row[i]->name == NULL ||
+          csa->deck && strlen(csa->P->row[i]->name) > 8)
+         sprintf(csa->field, "R%07d", i);
+      else
+      {  strcpy(csa->field, csa->P->row[i]->name);
+         for (f = csa->field; *f != '\0'; f++)
+            if (*f == ' ') *f = '_';
+      }
+      return csa->field;
+}
+
+static char *col_name(struct csa *csa, int j)
+{     /* make j-th column name */
+      char *f;
+      xassert(1 <= j && j <= csa->P->n);
+      if (csa->P->col[j]->name == NULL ||
+          csa->deck && strlen(csa->P->col[j]->name) > 8)
+         sprintf(csa->field, "C%07d", j);
+      else
+      {  strcpy(csa->field, csa->P->col[j]->name);
+         for (f = csa->field; *f != '\0'; f++)
+            if (*f == ' ') *f = '_';
+      }
+      return csa->field;
+}
+
+static char *mps_numb(struct csa *csa, double val)
+{     /* format floating-point number */
+      int dig;
+      char *exp;
+      for (dig = 12; dig >= 6; dig--)
+      {  if (val != 0.0 && fabs(val) < 0.002)
+            sprintf(csa->field, "%.*E", dig-1, val);
+         else
+            sprintf(csa->field, "%.*G", dig, val);
+         exp = strchr(csa->field, 'E');
+         if (exp != NULL)
+            sprintf(exp+1, "%d", atoi(exp+1));
+         if (strlen(csa->field) <= 12) break;
+      }
+      xassert(strlen(csa->field) <= 12);
+      return csa->field;
+}
+
+int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm,
+      const char *fname)
+{     /* write problem data in MPS format */
+      glp_mpscp _parm;
+      struct csa _csa, *csa = &_csa;
+      XFILE *fp;
+      int out_obj, one_col = 0, empty = 0;
+      int i, j, recno, marker, count, gap, ret;
+      xprintf("Writing problem data to `%s'...\n", fname);
+      if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE))
+         xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt);
+      if (parm == NULL)
+         glp_init_mpscp(&_parm), parm = &_parm;
+      /* check control parameters */
+      check_parm("glp_write_mps", parm);
+      /* initialize common storage area */
+      csa->P = P;
+      csa->deck = (fmt == GLP_MPS_DECK);
+      csa->parm = parm;
+      /* create output MPS file */
+      fp = xfopen(fname, "w"), recno = 0;
+      if (fp == NULL)
+      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* write comment records */
+      xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:",
+         P->name == NULL ? "" : P->name), recno++;
+      xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ?
+         "LP" : "MIP"), recno++;
+      xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++;
+      if (glp_get_num_int(P) == 0)
+         xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++;
+      else
+         xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n",
+            "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)),
+            recno++;
+      xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++;
+      xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" :
+         "Free MPS"), recno++;
+      xfprintf(fp, "*\n", recno++);
+      /* write NAME indicator record */
+      xfprintf(fp, "NAME%*s%s\n",
+         P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)),
+         recno++;
+#if 1
+      /* determine whether to write the objective row */
+      out_obj = 1;
+      for (i = 1; i <= P->m; i++)
+      {  if (P->row[i]->type == GLP_FR)
+         {  out_obj = 0;
+            break;
+         }
+      }
+#endif
+      /* write ROWS section */
+      xfprintf(fp, "ROWS\n"), recno++;
+      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
+      {  int type;
+         type = (i == 0 ? GLP_FR : P->row[i]->type);
+         if (type == GLP_FR)
+            type = 'N';
+         else if (type == GLP_LO)
+            type = 'G';
+         else if (type == GLP_UP)
+            type = 'L';
+         else if (type == GLP_DB || type == GLP_FX)
+            type = 'E';
+         else
+            xassert(type != type);
+         xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "",
+            row_name(csa, i)), recno++;
+      }
+      /* write COLUMNS section */
+      xfprintf(fp, "COLUMNS\n"), recno++;
+      marker = 0;
+      for (j = 1; j <= P->n; j++)
+      {  GLPAIJ cj, *aij;
+         int kind;
+         kind = P->col[j]->kind;
+         if (kind == GLP_CV)
+         {  if (marker % 2 == 1)
+            {  /* close current integer block */
+               marker++;
+               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
+                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+                  csa->deck ? 17 : 1, ""), recno++;
+            }
+         }
+         else if (kind == GLP_IV)
+         {  if (marker % 2 == 0)
+            {  /* open new integer block */
+               marker++;
+               xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n",
+                  csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+                  csa->deck ? 17 : 1, ""), recno++;
+            }
+         }
+         else
+            xassert(kind != kind);
+         if (out_obj && P->col[j]->coef != 0.0)
+         {  /* make fake objective coefficient */
+            aij = &cj;
+            aij->row = NULL;
+            aij->val = P->col[j]->coef;
+            aij->c_next = P->col[j]->ptr;
+         }
+         else
+            aij = P->col[j]->ptr;
+#if 1 /* FIXME */
+         if (aij == NULL)
+         {  /* empty column */
+            empty++;
+            xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+               csa->deck ? 8 : 1, col_name(csa, j));
+            /* we need a row */
+            xassert(P->m > 0);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, 1));
+            xfprintf(fp, "%*s0%*s$ empty column\n",
+               csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++;
+         }
+#endif
+         count = 0;
+         for (aij = aij; aij != NULL; aij = aij->c_next)
+         {  if (one_col || count % 2 == 0)
+               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+                  csa->deck ? 8 : 1, col_name(csa, j));
+            gap = (one_col || count % 2 == 0 ? 2 : 3);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, aij->row == NULL ? 0 : aij->row->i));
+            xfprintf(fp, "%*s%*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+               mps_numb(csa, aij->val)), count++;
+            if (one_col || count % 2 == 0)
+               xfprintf(fp, "\n"), recno++;
+         }
+         if (!(one_col || count % 2 == 0))
+            xfprintf(fp, "\n"), recno++;
+      }
+      if (marker % 2 == 1)
+      {  /* close last integer block */
+         marker++;
+         xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n",
+            csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "",
+            csa->deck ? 17 : 1, ""), recno++;
+      }
+#if 1
+      if (empty > 0)
+         xprintf("Warning: problem has %d empty column(s)\n", empty);
+#endif
+      /* write RHS section */
+      xfprintf(fp, "RHS\n"), recno++;
+      count = 0;
+      for (i = (out_obj ? 0 : 1); i <= P->m; i++)
+      {  int type;
+         double rhs;
+         if (i == 0)
+            rhs = P->c0;
+         else
+         {  type = P->row[i]->type;
+            if (type == GLP_FR)
+               rhs = 0.0;
+            else if (type == GLP_LO)
+               rhs = P->row[i]->lb;
+            else if (type == GLP_UP)
+               rhs = P->row[i]->ub;
+            else if (type == GLP_DB || type == GLP_FX)
+               rhs = P->row[i]->lb;
+            else
+               xassert(type != type);
+         }
+         if (rhs != 0.0)
+         {  if (one_col || count % 2 == 0)
+               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+                  csa->deck ? 8 : 1, "RHS1");
+            gap = (one_col || count % 2 == 0 ? 2 : 3);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, i));
+            xfprintf(fp, "%*s%*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+               mps_numb(csa, rhs)), count++;
+            if (one_col || count % 2 == 0)
+               xfprintf(fp, "\n"), recno++;
+         }
+      }
+      if (!(one_col || count % 2 == 0))
+         xfprintf(fp, "\n"), recno++;
+      /* write RANGES section */
+      for (i = P->m; i >= 1; i--)
+         if (P->row[i]->type == GLP_DB) break;
+      if (i == 0) goto bnds;
+      xfprintf(fp, "RANGES\n"), recno++;
+      count = 0;
+      for (i = 1; i <= P->m; i++)
+      {  if (P->row[i]->type == GLP_DB)
+         {  if (one_col || count % 2 == 0)
+               xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "",
+                  csa->deck ? 8 : 1, "RNG1");
+            gap = (one_col || count % 2 == 0 ? 2 : 3);
+            xfprintf(fp, "%*s%-*s",
+               csa->deck ? gap : 1, "", csa->deck ? 8 : 1,
+               row_name(csa, i));
+            xfprintf(fp, "%*s%*s",
+               csa->deck ? 2 : 1, "", csa->deck ? 12 : 1,
+               mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++;
+            if (one_col || count % 2 == 0)
+               xfprintf(fp, "\n"), recno++;
+         }
+      }
+      if (!(one_col || count % 2 == 0))
+         xfprintf(fp, "\n"), recno++;
+bnds: /* write BOUNDS section */
+      for (j = P->n; j >= 1; j--)
+         if (!(P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0))
+            break;
+      if (j == 0) goto endt;
+      xfprintf(fp, "BOUNDS\n"), recno++;
+      for (j = 1; j <= P->n; j++)
+      {  int type, data[2];
+         double bnd[2];
+         char *spec[2];
+         spec[0] = spec[1] = NULL;
+         type = P->col[j]->type;
+         if (type == GLP_FR)
+            spec[0] = "FR", data[0] = 0;
+         else if (type == GLP_LO)
+         {  if (P->col[j]->lb != 0.0)
+               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
+            if (P->col[j]->kind == GLP_IV)
+               spec[1] = "PL", data[1] = 0;
+         }
+         else if (type == GLP_UP)
+         {  spec[0] = "MI", data[0] = 0;
+            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
+         }
+         else if (type == GLP_DB)
+         {  if (P->col[j]->lb != 0.0)
+               spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb;
+            spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub;
+         }
+         else if (type == GLP_FX)
+            spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb;
+         else
+            xassert(type != type);
+         for (i = 0; i <= 1; i++)
+         {  if (spec[i] != NULL)
+            {  xfprintf(fp, " %s %-*s%*s%-*s", spec[i],
+                  csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "",
+                  csa->deck ? 8 : 1, col_name(csa, j));
+               if (data[i])
+                  xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "",
+                     csa->deck ? 12 : 1, mps_numb(csa, bnd[i]));
+               xfprintf(fp, "\n"), recno++;
+            }
+         }
+      }
+endt: /* write ENDATA indicator record */
+      xfprintf(fp, "ENDATA\n"), recno++;
+      xfflush(fp);
+      if (xferror(fp))
+      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
+         ret = 1;
+         goto done;
+      }
+      /* problem data has been successfully written */
+      xprintf("%d records were written\n", recno);
+      ret = 0;
+done: if (fp != NULL) xfclose(fp);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpnet.h
===================================================================
--- deps/glpk/src/glpnet.h	(revision 9)
+++ deps/glpk/src/glpnet.h	(revision 9)
@@ -0,0 +1,60 @@
+/* glpnet.h (graph and network algorithms) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPNET_H
+#define GLPNET_H
+
+#define mc21a _glp_mc21a
+int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+      int iperm[], int pr[], int arp[], int cv[], int out[]);
+/* permutations for zero-free diagonal */
+
+#define mc13d _glp_mc13d
+int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+      int ior[], int ib[], int lowl[], int numb[], int prev[]);
+/* permutations to block triangular form */
+
+#define okalg _glp_okalg
+int okalg(int nv, int na, const int tail[], const int head[],
+      const int low[], const int cap[], const int cost[], int x[],
+      int pi[]);
+/* out-of-kilter algorithm */
+
+#define ffalg _glp_ffalg
+void ffalg(int nv, int na, const int tail[], const int head[],
+      int s, int t, const int cap[], int x[], char cut[]);
+/* Ford-Fulkerson algorithm */
+
+#define wclique _glp_wclique
+int wclique(int n, const int w[], const unsigned char a[], int ind[]);
+/* find maximum weight clique with Ostergard's algorithm */
+
+#define kellerman _glp_kellerman
+int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+      void *info, void /* glp_graph */ *H);
+/* cover edges by cliques with Kellerman's heuristic */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpnet01.c
===================================================================
--- deps/glpk/src/glpnet01.c	(revision 9)
+++ deps/glpk/src/glpnet01.c	(revision 9)
@@ -0,0 +1,301 @@
+/* glpnet01.c (permutations for zero-free diagonal) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is the result of translation of the Fortran subroutines
+*  MC21A and MC21B associated with the following paper:
+*
+*  I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM
+*  Trans. on Math. Softw. 7 (1981), 387-390.
+*
+*  Use of ACM Algorithms is subject to the ACM Software Copyright and
+*  License Agreement. See <http://www.acm.org/publications/policies>.
+*
+*  The translation was made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  mc21a - permutations for zero-free diagonal
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+*     int iperm[], int pr[], int arp[], int cv[], int out[]);
+*
+*  DESCRIPTION
+*
+*  Given the pattern of nonzeros of a sparse matrix, the routine mc21a
+*  attempts to find a permutation of its rows that makes the matrix have
+*  no zeros on its diagonal.
+*
+*  INPUT PARAMETERS
+*
+*  n     order of matrix.
+*
+*  icn   array containing the column indices of the non-zeros. Those
+*        belonging to a single row must be contiguous but the ordering
+*        of column indices within each row is unimportant and wasted
+*        space between rows is permitted.
+*
+*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the
+*        first column index of a non-zero in row i.
+*
+*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
+*
+*  OUTPUT PARAMETER
+*
+*  iperm contains permutation to make diagonal have the smallest
+*        number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n,
+*        are non-zero at the end of the algorithm unless the matrix is
+*        structurally singular. In this case, (iperm[i], i) will be
+*        zero for n - numnz entries.
+*
+*  WORKING ARRAYS
+*
+*  pr    working array of length [1+n], where pr[0] is not used.
+*        pr[i] is the previous row to i in the depth first search.
+*
+*  arp   working array of length [1+n], where arp[0] is not used.
+*        arp[i] is one less than the number of non-zeros in row i which
+*        have not been scanned when looking for a cheap assignment.
+*
+*  cv    working array of length [1+n], where cv[0] is not used.
+*        cv[i] is the most recent row extension at which column i was
+*        visited.
+*
+*  out   working array of length [1+n], where out[0] is not used.
+*        out[i] is one less than the number of non-zeros in row i
+*        which have not been scanned during one pass through the main
+*        loop.
+*
+*  RETURNS
+*
+*  The routine mc21a returns numnz, the number of non-zeros on diagonal
+*  of permuted matrix. */
+
+int mc21a(int n, const int icn[], const int ip[], const int lenr[],
+      int iperm[], int pr[], int arp[], int cv[], int out[])
+{     int i, ii, in1, in2, j, j1, jord, k, kk, numnz;
+      /* Initialization of arrays. */
+      for (i = 1; i <= n; i++)
+      {  arp[i] = lenr[i] - 1;
+         cv[i] = iperm[i] = 0;
+      }
+      numnz = 0;
+      /* Main loop. */
+      /* Each pass round this loop either results in a new assignment
+         or gives a row with no assignment. */
+      for (jord = 1; jord <= n; jord++)
+      {  j = jord;
+         pr[j] = -1;
+         for (k = 1; k <= jord; k++)
+         {  /* Look for a cheap assignment. */
+            in1 = arp[j];
+            if (in1 >= 0)
+            {  in2 = ip[j] + lenr[j] - 1;
+               in1 = in2 - in1;
+               for (ii = in1; ii <= in2; ii++)
+               {  i = icn[ii];
+                  if (iperm[i] == 0) goto L110;
+               }
+               /* No cheap assignment in row. */
+               arp[j] = -1;
+            }
+            /* Begin looking for assignment chain starting with row j.*/
+            out[j] = lenr[j] - 1;
+            /* Inner loop. Extends chain by one or backtracks. */
+            for (kk = 1; kk <= jord; kk++)
+            {  in1 = out[j];
+               if (in1 >= 0)
+               {  in2 = ip[j] + lenr[j] - 1;
+                  in1 = in2 - in1;
+                  /* Forward scan. */
+                  for (ii = in1; ii <= in2; ii++)
+                  {  i = icn[ii];
+                     if (cv[i] != jord)
+                     {  /* Column i has not yet been accessed during
+                           this pass. */
+                        j1 = j;
+                        j = iperm[i];
+                        cv[i] = jord;
+                        pr[j] = j1;
+                        out[j1] = in2 - ii - 1;
+                        goto L100;
+                     }
+                  }
+               }
+               /* Backtracking step. */
+               j = pr[j];
+               if (j == -1) goto L130;
+            }
+L100:       ;
+         }
+L110:    /* New assignment is made. */
+         iperm[i] = j;
+         arp[j] = in2 - ii - 1;
+         numnz++;
+         for (k = 1; k <= jord; k++)
+         {  j = pr[j];
+            if (j == -1) break;
+            ii = ip[j] + lenr[j] - out[j] - 2;
+            i = icn[ii];
+            iperm[i] = j;
+         }
+L130:    ;
+      }
+      /* If matrix is structurally singular, we now complete the
+         permutation iperm. */
+      if (numnz < n)
+      {  for (i = 1; i <= n; i++)
+            arp[i] = 0;
+         k = 0;
+         for (i = 1; i <= n; i++)
+         {  if (iperm[i] == 0)
+               out[++k] = i;
+            else
+               arp[iperm[i]] = i;
+         }
+         k = 0;
+         for (i = 1; i <= n; i++)
+         {  if (arp[i] == 0)
+               iperm[out[++k]] = i;
+         }
+      }
+      return numnz;
+}
+
+/**********************************************************************/
+
+#if 0
+#include "glplib.h"
+
+int sing;
+
+void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
+      int iw[]);
+
+void fa01bs(int max, int *nrand);
+
+int main(void)
+{     /* test program for the routine mc21a */
+      /* these runs on random matrices cause all possible statements in
+         mc21a to be executed */
+      int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz;
+      int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80];
+      licn = 1000;
+      /* run on random matrices of orders 1 through 20 */
+      for (n = 1; n <= 20; n++)
+      {  nov4 = n / 4;
+         if (nov4 < 1) nov4 = 1;
+L10:     fa01bs(nov4, &l);
+         knum = l * n;
+         /* knum is requested number of non-zeros in random matrix */
+         if (knum > licn) goto L10;
+         /* if sing is false, matrix is guaranteed structurally
+            non-singular */
+         sing = ((n / 2) * 2 == n);
+         /* call to subroutine to generate random matrix */
+         ranmat(n, n, icn, ip, n+1, &knum, iw1);
+         /* knum is now actual number of non-zeros in random matrix */
+         if (knum > licn) goto L10;
+         xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing);
+         /* set up array of row lengths */
+         for (i = 1; i <= n; i++)
+            lenr[i] = ip[i+1] - ip[i];
+         /* call to mc21a */
+         numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n],
+            &iw1[n+n], &iw1[n+n+n]);
+         /* testing to see if there are numnz non-zeros on the diagonal
+            of the permuted matrix. */
+         num = 0;
+         for (i = 1; i <= n; i++)
+         {  iold = iperm[i];
+            j1 = ip[iold];
+            j2 = j1 + lenr[iold] - 1;
+            if (j2 < j1) continue;
+            for (jj = j1; jj <= j2; jj++)
+            {  j = icn[jj];
+               if (j == i)
+               {  num++;
+                  break;
+               }
+            }
+         }
+         if (num != numnz)
+            xprintf("Failure in mc21a, numnz = %d instead of %d\n",
+               numnz, num);
+      }
+      return 0;
+}
+
+void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum,
+      int iw[])
+{     /* subroutine to generate random matrix */
+      int i, ii, inum, j, lrow, matnum;
+      inum = (*knum / n) * 2;
+      if (inum > n-1) inum = n-1;
+      matnum = 1;
+      /* each pass through this loop generates a row of the matrix */
+      for (j = 1; j <= m; j++)
+      {  iptr[j] = matnum;
+         if (!(sing || j > n))
+            icn[matnum++] = j;
+         if (n == 1) continue;
+         for (i = 1; i <= n; i++) iw[i] = 0;
+         if (!sing) iw[j] = 1;
+         fa01bs(inum, &lrow);
+         lrow--;
+         if (lrow == 0) continue;
+         /* lrow off-diagonal non-zeros in row j of the matrix */
+         for (ii = 1; ii <= lrow; ii++)
+         {  for (;;)
+            {  fa01bs(n, &i);
+               if (iw[i] != 1) break;
+            }
+            iw[i] = 1;
+            icn[matnum++] = i;
+         }
+      }
+      for (i = m+1; i <= nnnp1; i++)
+         iptr[i] = matnum;
+      *knum = matnum - 1;
+      return;
+}
+
+double g = 1431655765.0;
+
+double fa01as(int i)
+{     /* random number generator */
+      g = fmod(g * 9228907.0, 4294967296.0);
+      if (i >= 0)
+         return g / 4294967296.0;
+      else
+         return 2.0 * g / 4294967296.0 - 1.0;
+}
+
+void fa01bs(int max, int *nrand)
+{     *nrand = (int)(fa01as(1) * (double)max) + 1;
+      return;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpnet02.c
===================================================================
--- deps/glpk/src/glpnet02.c	(revision 9)
+++ deps/glpk/src/glpnet02.c	(revision 9)
@@ -0,0 +1,314 @@
+/* glpnet02.c (permutations to block triangular form) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is the result of translation of the Fortran subroutines
+*  MC13D and MC13E associated with the following paper:
+*
+*  I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular
+*  form, ACM Trans. on Math. Softw. 4 (1978), 189-192.
+*
+*  Use of ACM Algorithms is subject to the ACM Software Copyright and
+*  License Agreement. See <http://www.acm.org/publications/policies>.
+*
+*  The translation was made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  mc13d - permutations to block triangular form
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+*     int ior[], int ib[], int lowl[], int numb[], int prev[]);
+*
+*  DESCRIPTION
+*
+*  Given the column numbers of the nonzeros in each row of the sparse
+*  matrix, the routine mc13d finds a symmetric permutation that makes
+*  the matrix block lower triangular.
+*
+*  INPUT PARAMETERS
+*
+*  n     order of the matrix.
+*
+*  icn   array containing the column indices of the non-zeros. Those
+*        belonging to a single row must be contiguous but the ordering
+*        of column indices within each row is unimportant and wasted
+*        space between rows is permitted.
+*
+*  ip    ip[i], i = 1,2,...,n, is the position in array icn of the
+*        first column index of a non-zero in row i.
+*
+*  lenr  lenr[i], i = 1,2,...,n, is the number of non-zeros in row i.
+*
+*  OUTPUT PARAMETERS
+*
+*  ior   ior[i], i = 1,2,...,n, gives the position on the original
+*        ordering of the row or column which is in position i in the
+*        permuted form.
+*
+*  ib    ib[i], i = 1,2,...,num, is the row number in the permuted
+*        matrix of the beginning of block i, 1 <= num <= n.
+*
+*  WORKING ARRAYS
+*
+*  arp   working array of length [1+n], where arp[0] is not used.
+*        arp[i] is one less than the number of unsearched edges leaving
+*        node i. At the end of the algorithm it is set to a permutation
+*        which puts the matrix in block lower triangular form.
+*
+*  ib    working array of length [1+n], where ib[0] is not used.
+*        ib[i] is the position in the ordering of the start of the ith
+*        block. ib[n+1-i] holds the node number of the ith node on the
+*        stack.
+*
+*  lowl  working array of length [1+n], where lowl[0] is not used.
+*        lowl[i] is the smallest stack position of any node to which a
+*        path from node i has been found. It is set to n+1 when node i
+*        is removed from the stack.
+*
+*  numb  working array of length [1+n], where numb[0] is not used.
+*        numb[i] is the position of node i in the stack if it is on it,
+*        is the permuted order of node i for those nodes whose final
+*        position has been found and is otherwise zero.
+*
+*  prev  working array of length [1+n], where prev[0] is not used.
+*        prev[i] is the node at the end of the path when node i was
+*        placed on the stack.
+*
+*  RETURNS
+*
+*  The routine mc13d returns num, the number of blocks found. */
+
+int mc13d(int n, const int icn[], const int ip[], const int lenr[],
+      int ior[], int ib[], int lowl[], int numb[], int prev[])
+{     int *arp = ior;
+      int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt,
+         nnm1, num, stp;
+      /* icnt is the number of nodes whose positions in final ordering
+         have been found. */
+      icnt = 0;
+      /* num is the number of blocks that have been found. */
+      num = 0;
+      nnm1 = n + n - 1;
+      /* Initialization of arrays. */
+      for (j = 1; j <= n; j++)
+      {  numb[j] = 0;
+         arp[j] = lenr[j] - 1;
+      }
+      for (isn = 1; isn <= n; isn++)
+      {  /* Look for a starting node. */
+         if (numb[isn] != 0) continue;
+         iv = isn;
+         /* ist is the number of nodes on the stack ... it is the stack
+            pointer. */
+         ist = 1;
+         /* Put node iv at beginning of stack. */
+         lowl[iv] = numb[iv] = 1;
+         ib[n] = iv;
+         /* The body of this loop puts a new node on the stack or
+            backtracks. */
+         for (dummy = 1; dummy <= nnm1; dummy++)
+         {  i1 = arp[iv];
+            /* Have all edges leaving node iv been searched? */
+            if (i1 >= 0)
+            {  i2 = ip[iv] + lenr[iv] - 1;
+               i1 = i2 - i1;
+               /* Look at edges leaving node iv until one enters a new
+                  node or all edges are exhausted. */
+               for (ii = i1; ii <= i2; ii++)
+               {  iw = icn[ii];
+                  /* Has node iw been on stack already? */
+                  if (numb[iw] == 0) goto L70;
+                  /* Update value of lowl[iv] if necessary. */
+                  if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
+               }
+               /* There are no more edges leaving node iv. */
+               arp[iv] = -1;
+            }
+            /* Is node iv the root of a block? */
+            if (lowl[iv] < numb[iv]) goto L60;
+            /* Order nodes in a block. */
+            num++;
+            ist1 = n + 1 - ist;
+            lcnt = icnt + 1;
+            /* Peel block off the top of the stack starting at the top
+               and working down to the root of the block. */
+            for (stp = ist1; stp <= n; stp++)
+            {  iw = ib[stp];
+               lowl[iw] = n + 1;
+               numb[iw] = ++icnt;
+               if (iw == iv) break;
+            }
+            ist = n - stp;
+            ib[num] = lcnt;
+            /* Are there any nodes left on the stack? */
+            if (ist != 0) goto L60;
+            /* Have all the nodes been ordered? */
+            if (icnt < n) break;
+            goto L100;
+L60:        /* Backtrack to previous node on path. */
+            iw = iv;
+            iv = prev[iv];
+            /* Update value of lowl[iv] if necessary. */
+            if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw];
+            continue;
+L70:        /* Put new node on the stack. */
+            arp[iv] = i2 - ii - 1;
+            prev[iw] = iv;
+            iv = iw;
+            lowl[iv] = numb[iv] = ++ist;
+            ib[n+1-ist] = iv;
+         }
+      }
+L100: /* Put permutation in the required form. */
+      for (i = 1; i <= n; i++)
+         arp[numb[i]] = i;
+      return num;
+}
+
+/**********************************************************************/
+
+#if 0
+#include "glplib.h"
+
+void test(int n, int ipp);
+
+int main(void)
+{     /* test program for routine mc13d */
+      test( 1,   0);
+      test( 2,   1);
+      test( 2,   2);
+      test( 3,   3);
+      test( 4,   4);
+      test( 5,  10);
+      test(10,  10);
+      test(10,  20);
+      test(20,  20);
+      test(20,  50);
+      test(50,  50);
+      test(50, 200);
+      return 0;
+}
+
+void fa01bs(int max, int *nrand);
+
+void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]);
+
+void test(int n, int ipp)
+{     int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150],
+         lenr[1+50];
+      char a[1+50][1+50], hold[1+100];
+      int i, ii, iblock, ij, index, j, jblock, jj, k9, num;
+      xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-"
+         "zeros\n", n, ipp);
+      for (j = 1; j <= n; j++)
+      {  for (i = 1; i <= n; i++)
+            a[i][j] = 0;
+         a[j][j] = 1;
+      }
+      for (k9 = 1; k9 <= ipp; k9++)
+      {  /* these statements should be replaced by calls to your
+            favorite random number generator to place two pseudo-random
+            numbers between 1 and n in the variables i and j */
+         for (;;)
+         {  fa01bs(n, &i);
+            fa01bs(n, &j);
+            if (!a[i][j]) break;
+         }
+         a[i][j] = 1;
+      }
+      /* setup converts matrix a[i,j] to required sparsity-oriented
+         storage format */
+      setup(n, a, ip, icn, lenr);
+      num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]);
+      /* output reordered matrix with blocking to improve clarity */
+      xprintf("\nThe reordered matrix which has %d block%s is of the fo"
+         "rm\n", num, num == 1 ? "" : "s");
+      ib[num+1] = n + 1;
+      index = 100;
+      iblock = 1;
+      for (i = 1; i <= n; i++)
+      {  for (ij = 1; ij <= index; ij++)
+            hold[ij] = ' ';
+         if (i == ib[iblock])
+         {  xprintf("\n");
+            iblock++;
+         }
+         jblock = 1;
+         index = 0;
+         for (j = 1; j <= n; j++)
+         {  if (j == ib[jblock])
+            {  hold[++index] = ' ';
+               jblock++;
+            }
+            ii = ior[i];
+            jj = ior[j];
+            hold[++index] = (char)(a[ii][jj] ? 'X' : '0');
+         }
+         xprintf("%.*s\n", index, &hold[1]);
+      }
+      xprintf("\nThe starting point for each block is given by\n");
+      for (i = 1; i <= num; i++)
+      {  if ((i - 1) % 12 == 0) xprintf("\n");
+         xprintf(" %4d", ib[i]);
+      }
+      xprintf("\n");
+      return;
+}
+
+void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[])
+{     int i, j, ind;
+      for (i = 1; i <= n; i++)
+         lenr[i] = 0;
+      ind = 1;
+      for (i = 1; i <= n; i++)
+      {  ip[i] = ind;
+         for (j = 1; j <= n; j++)
+         {  if (a[i][j])
+            {  lenr[i]++;
+               icn[ind++] = j;
+            }
+         }
+      }
+      return;
+}
+
+double g = 1431655765.0;
+
+double fa01as(int i)
+{     /* random number generator */
+      g = fmod(g * 9228907.0, 4294967296.0);
+      if (i >= 0)
+         return g / 4294967296.0;
+      else
+         return 2.0 * g / 4294967296.0 - 1.0;
+}
+
+void fa01bs(int max, int *nrand)
+{     *nrand = (int)(fa01as(1) * (double)max) + 1;
+      return;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpnet03.c
===================================================================
--- deps/glpk/src/glpnet03.c	(revision 9)
+++ deps/glpk/src/glpnet03.c	(revision 9)
@@ -0,0 +1,776 @@
+/* glpnet03.c (Klingman's network problem generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is the result of translation of the Fortran program NETGEN
+*  developed by Dr. Darwin Klingman, which is publically available from
+*  NETLIB at <http://www.netlib.org/lp/generators>.
+*
+*  The translation was made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_netgen - Klingman's network problem generator
+*
+*  SYNOPSIS
+*
+*  int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+*     const int parm[1+15]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_netgen is a network problem generator developed by
+*  Dr. Darwin Klingman. It can create capacitated and uncapacitated
+*  minimum cost flow (or transshipment), transportation, and assignment
+*  problems.
+*
+*  The parameter G specifies the graph object, to which the generated
+*  problem data have to be stored. Note that on entry the graph object
+*  is erased with the routine glp_erase_graph.
+*
+*  The parameter v_rhs specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores the supply or
+*  demand value. If v_rhs < 0, the value is not stored.
+*
+*  The parameter a_cap specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the arc capacity.
+*  If a_cap < 0, the capacity is not stored.
+*
+*  The parameter a_cost specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the per-unit cost
+*  if the arc flow. If a_cost < 0, the cost is not stored.
+*
+*  The array parm contains description of the network to be generated:
+*
+*  parm[0]           not used
+*  parm[1]  (iseed)  8-digit positive random number seed
+*  parm[2]  (nprob)  8-digit problem id number
+*  parm[3]  (nodes)  total number of nodes
+*  parm[4]  (nsorc)  total number of source nodes (including
+*                    transshipment nodes)
+*  parm[5]  (nsink)  total number of sink nodes (including
+*                    transshipment nodes)
+*  parm[6]  (iarcs)  number of arcs
+*  parm[7]  (mincst) minimum cost for arcs
+*  parm[8]  (maxcst) maximum cost for arcs
+*  parm[9]  (itsup)  total supply
+*  parm[10] (ntsorc) number of transshipment source nodes
+*  parm[11] (ntsink) number of transshipment sink nodes
+*  parm[12] (iphic)  percentage of skeleton arcs to be given
+*                    the maximum cost
+*  parm[13] (ipcap)  percentage of arcs to be capacitated
+*  parm[14] (mincap) minimum upper bound for capacitated arcs
+*  parm[15] (maxcap) maximum upper bound for capacitated arcs
+*
+*  The routine generates a transportation problem if:
+*
+*     nsorc + nsink = nodes, ntsorc = 0, and ntsink = 0.
+*
+*  The routine generates an assignment problem if the requirements for
+*  a transportation problem are met and:
+*
+*     nsorc = nsink and itsup = nsorc.
+*
+*  RETURNS
+*
+*  If the instance was successfully generated, the routine glp_netgen
+*  returns zero; otherwise, if specified parameters are inconsistent,
+*  the routine returns a non-zero error code.
+*
+*  REFERENCES
+*
+*  D.Klingman, A.Napier, and J.Stutz. NETGEN: A program for generating
+*  large scale capacitated assignment, transportation, and minimum cost
+*  flow networks. Management Science 20 (1974), 814-20. */
+
+struct csa
+{     /* common storage area */
+      glp_graph *G;
+      int v_rhs, a_cap, a_cost;
+      int nodes, iarcs, mincst, maxcst, itsup, nsorc, nsink, nonsor,
+         nfsink, narcs, nsort, nftsor, ipcap, mincap, maxcap, ktl,
+         nodlft, *ipred, *ihead, *itail, *iflag, *isup, *lsinks, mult,
+         modul, i15, i16, jran;
+};
+
+#define G      (csa->G)
+#define v_rhs  (csa->v_rhs)
+#define a_cap  (csa->a_cap)
+#define a_cost (csa->a_cost)
+#define nodes  (csa->nodes)
+#define iarcs  (csa->iarcs)
+#define mincst (csa->mincst)
+#define maxcst (csa->maxcst)
+#define itsup  (csa->itsup)
+#define nsorc  (csa->nsorc)
+#define nsink  (csa->nsink)
+#define nonsor (csa->nonsor)
+#define nfsink (csa->nfsink)
+#define narcs  (csa->narcs)
+#define nsort  (csa->nsort)
+#define nftsor (csa->nftsor)
+#define ipcap  (csa->ipcap)
+#define mincap (csa->mincap)
+#define maxcap (csa->maxcap)
+#define ktl    (csa->ktl)
+#define nodlft (csa->nodlft)
+#if 0
+/* spent a day to find out this bug */
+#define ist    (csa->ist)
+#else
+#define ist    (ipred[0])
+#endif
+#define ipred  (csa->ipred)
+#define ihead  (csa->ihead)
+#define itail  (csa->itail)
+#define iflag  (csa->iflag)
+#define isup   (csa->isup)
+#define lsinks (csa->lsinks)
+#define mult   (csa->mult)
+#define modul  (csa->modul)
+#define i15    (csa->i15)
+#define i16    (csa->i16)
+#define jran   (csa->jran)
+
+static void cresup(struct csa *csa);
+static void chain(struct csa *csa, int lpick, int lsorc);
+static void chnarc(struct csa *csa, int lsorc);
+static void sort(struct csa *csa);
+static void pickj(struct csa *csa, int it);
+static void assign(struct csa *csa);
+static void setran(struct csa *csa, int iseed);
+static int iran(struct csa *csa, int ilow, int ihigh);
+
+int glp_netgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
+      const int parm[1+15])
+{     struct csa _csa, *csa = &_csa;
+      int iseed, nprob, ntsorc, ntsink, iphic, i, nskel, nltr, ltsink,
+         ntrans, npsink, nftr, npsorc, ntravl, ntrrem, lsorc, lpick,
+         nsksr, nsrchn, j, item, l, ks, k, ksp, li, n, ii, it, ih, icap,
+         jcap, icost, jcost, ret;
+      G = G_;
+      v_rhs = _v_rhs;
+      a_cap = _a_cap;
+      a_cost = _a_cost;
+      if (G != NULL)
+      {  if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+            xerror("glp_netgen: v_rhs = %d; invalid offset\n", v_rhs);
+         if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+            xerror("glp_netgen: a_cap = %d; invalid offset\n", a_cap);
+         if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+            xerror("glp_netgen: a_cost = %d; invalid offset\n", a_cost);
+      }
+      /* Input the user's random number seed and fix it if
+         non-positive. */
+      iseed = parm[1];
+      nprob = parm[2];
+      if (iseed <= 0) iseed = 13502460;
+      setran(csa, iseed);
+      /* Input the user's problem characteristics. */
+      nodes = parm[3];
+      nsorc = parm[4];
+      nsink = parm[5];
+      iarcs = parm[6];
+      mincst = parm[7];
+      maxcst = parm[8];
+      itsup = parm[9];
+      ntsorc = parm[10];
+      ntsink = parm[11];
+      iphic = parm[12];
+      ipcap = parm[13];
+      mincap = parm[14];
+      maxcap = parm[15];
+      /* Check the size of the problem. */
+      if (!(10 <= nodes && nodes <= 100000))
+      {  ret = 1;
+         goto done;
+      }
+      /* Check user supplied parameters for consistency. */
+      if (!(nsorc >= 0 && nsink >= 0 && nsorc + nsink <= nodes))
+      {  ret = 2;
+         goto done;
+      }
+      if (iarcs < 0)
+      {  ret = 3;
+         goto done;
+      }
+      if (mincst > maxcst)
+      {  ret = 4;
+         goto done;
+      }
+      if (itsup < 0)
+      {  ret = 5;
+         goto done;
+      }
+      if (!(0 <= ntsorc && ntsorc <= nsorc))
+      {  ret = 6;
+         goto done;
+      }
+      if (!(0 <= ntsink && ntsink <= nsink))
+      {  ret = 7;
+         goto done;
+      }
+      if (!(0 <= iphic && iphic <= 100))
+      {  ret = 8;
+         goto done;
+      }
+      if (!(0 <= ipcap && ipcap <= 100))
+      {  ret = 9;
+         goto done;
+      }
+      if (mincap > maxcap)
+      {  ret = 10;
+         goto done;
+      }
+      /* Initailize the graph object. */
+      if (G != NULL)
+      {  glp_erase_graph(G, G->v_size, G->a_size);
+         glp_add_vertices(G, nodes);
+         if (v_rhs >= 0)
+         {  double zero = 0.0;
+            for (i = 1; i <= nodes; i++)
+            {  glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
+            }
+         }
+      }
+      /* Allocate working arrays. */
+      ipred = xcalloc(1+nodes, sizeof(int));
+      ihead = xcalloc(1+nodes, sizeof(int));
+      itail = xcalloc(1+nodes, sizeof(int));
+      iflag = xcalloc(1+nodes, sizeof(int));
+      isup = xcalloc(1+nodes, sizeof(int));
+      lsinks = xcalloc(1+nodes, sizeof(int));
+      /* Print the problem documentation records. */
+      if (G == NULL)
+      {  xprintf("BEGIN\n");
+         xprintf("NETGEN PROBLEM%8d%10s%10d NODES AND%10d ARCS\n",
+            nprob, "", nodes, iarcs);
+         xprintf("USER:%11d%11d%11d%11d%11d%11d\nDATA:%11d%11d%11d%11d%"
+            "11d%11d\n", iseed, nsorc, nsink, mincst,
+            maxcst, itsup, ntsorc, ntsink, iphic, ipcap,
+            mincap, maxcap);
+      }
+      else
+         glp_set_graph_name(G, "NETGEN");
+      /* Set various constants used in the program. */
+      narcs = 0;
+      nskel = 0;
+      nltr = nodes - nsink;
+      ltsink = nltr + ntsink;
+      ntrans = nltr - nsorc;
+      nfsink = nltr + 1;
+      nonsor = nodes - nsorc + ntsorc;
+      npsink = nsink - ntsink;
+      nodlft = nodes - nsink + ntsink;
+      nftr = nsorc + 1;
+      nftsor = nsorc - ntsorc + 1;
+      npsorc = nsorc - ntsorc;
+      /* Randomly distribute the supply among the source nodes. */
+      if (npsorc + npsink == nodes && npsorc == npsink &&
+          itsup == nsorc)
+      {  assign(csa);
+         nskel = nsorc;
+         goto L390;
+      }
+      cresup(csa);
+      /* Print the supply records. */
+      if (G == NULL)
+      {  xprintf("SUPPLY\n");
+         for (i = 1; i <= nsorc; i++)
+            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
+         xprintf("ARCS\n");
+      }
+      else
+      {  if (v_rhs >= 0)
+         {  for (i = 1; i <= nsorc; i++)
+            {  double temp = (double)isup[i];
+               glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      /* Make the sources point to themselves in ipred array. */
+      for (i = 1; i <= nsorc; i++)
+         ipred[i] = i;
+      if (ntrans == 0) goto L170;
+      /* Chain the transshipment nodes together in the ipred array. */
+      ist = nftr;
+      ipred[nltr] = 0;
+      for (i = nftr; i < nltr; i++)
+         ipred[i] = i+1;
+      /* Form even length chains for 60 percent of the transshipments.*/
+      ntravl = 6 * ntrans / 10;
+      ntrrem = ntrans - ntravl;
+L140: lsorc = 1;
+      while (ntravl != 0)
+      {  lpick = iran(csa, 1, ntravl + ntrrem);
+         ntravl--;
+         chain(csa, lpick, lsorc);
+         if (lsorc == nsorc) goto L140;
+         lsorc++;
+      }
+      /* Add the remaining transshipments to the chains. */
+      while (ntrrem != 0)
+      {
+         lpick = iran(csa, 1, ntrrem);
+         ntrrem--;
+         lsorc = iran(csa, 1, nsorc);
+         chain(csa, lpick, lsorc);
+      }
+L170: /* Set all demands equal to zero. */
+      for (i = nfsink; i <= nodes; i++)
+         ipred[i] = 0;
+      /* The following loop takes one chain at a time (through the use
+         of logic contained in the loop and calls to other routines) and
+         creates the remaining network arcs. */
+      for (lsorc = 1; lsorc <= nsorc; lsorc++)
+      {  chnarc(csa, lsorc);
+         for (i = nfsink; i <= nodes; i++)
+            iflag[i] = 0;
+         /* Choose the number of sinks to be hooked up to the current
+            chain. */
+         if (ntrans != 0)
+            nsksr = (nsort * 2 * nsink) / ntrans;
+         else
+            nsksr = nsink / nsorc + 1;
+         if (nsksr < 2) nsksr = 2;
+         if (nsksr > nsink) nsksr = nsink;
+         nsrchn = nsort;
+         /* Randomly pick nsksr sinks and put their names in lsinks. */
+         ktl = nsink;
+         for (j = 1; j <= nsksr; j++)
+         {  item = iran(csa, 1, ktl);
+            ktl--;
+            for (l = nfsink; l <= nodes; l++)
+            {  if (iflag[l] != 1)
+               {  item--;
+                  if (item == 0) goto L230;
+               }
+            }
+            break;
+L230:       lsinks[j] = l;
+            iflag[l] = 1;
+         }
+         /* If last source chain, add all sinks with zero demand to
+            lsinks list. */
+         if (lsorc == nsorc)
+         {  for (j = nfsink; j <= nodes; j++)
+            {  if (ipred[j] == 0 && iflag[j] != 1)
+               {  nsksr++;
+                  lsinks[nsksr] = j;
+                  iflag[j] = 1;
+               }
+            }
+         }
+         /* Create demands for group of sinks in lsinks. */
+         ks = isup[lsorc] / nsksr;
+         k = ipred[lsorc];
+         for (i = 1; i <= nsksr; i++)
+         {  nsort++;
+            ksp = iran(csa, 1, ks);
+            j = iran(csa, 1, nsksr);
+            itail[nsort] = k;
+            li = lsinks[i];
+            ihead[nsort] = li;
+            ipred[li] += ksp;
+            li = lsinks[j];
+            ipred[li] += ks - ksp;
+            n = iran(csa, 1, nsrchn);
+            k = lsorc;
+            for (ii = 1; ii <= n; ii++)
+               k = ipred[k];
+         }
+         li = lsinks[1];
+         ipred[li] += isup[lsorc] - ks * nsksr;
+         nskel += nsort;
+         /* Sort the arcs in the chain from source lsorc using itail as
+            sort key. */
+         sort(csa);
+         /* Print this part of skeleton and create the arcs for these
+            nodes. */
+         i = 1;
+         itail[nsort+1] = 0;
+L300:    for (j = nftsor; j <= nodes; j++)
+            iflag[j] = 0;
+         ktl = nonsor - 1;
+         it = itail[i];
+         iflag[it] = 1;
+L320:    ih = ihead[i];
+         iflag[ih] = 1;
+         narcs++;
+         ktl--;
+         /* Determine if this skeleton arc should be capacitated. */
+         icap = itsup;
+         jcap = iran(csa, 1, 100);
+         if (jcap <= ipcap)
+         {  icap = isup[lsorc];
+            if (mincap > icap) icap = mincap;
+         }
+         /* Determine if this skeleton arc should have the maximum
+            cost. */
+         icost = maxcst;
+         jcost = iran(csa, 1, 100);
+         if (jcost > iphic)
+            icost = iran(csa, mincst, maxcst);
+         if (G == NULL)
+            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ih, "", icost,
+               icap);
+         else
+         {  glp_arc *a = glp_add_arc(G, it, ih);
+            if (a_cap >= 0)
+            {  double temp = (double)icap;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)icost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+         i++;
+         if (itail[i] == it) goto L320;
+         pickj(csa, it);
+         if (i <= nsort) goto L300;
+      }
+      /* Create arcs from the transshipment sinks. */
+      if (ntsink != 0)
+      {  for (i = nfsink; i <= ltsink; i++)
+         {  for (j = nftsor; j <= nodes; j++)
+               iflag[j] = 0;
+            ktl = nonsor - 1;
+            iflag[i] = 1;
+            pickj(csa, i);
+         }
+      }
+L390: /* Print the demand records and end record. */
+      if (G == NULL)
+      {  xprintf("DEMAND\n");
+         for (i = nfsink; i <= nodes; i++)
+            xprintf("%6s%6d%18s%10d\n", "", i, "", ipred[i]);
+         xprintf("END\n");
+      }
+      else
+      {  if (v_rhs >= 0)
+         {  for (i = nfsink; i <= nodes; i++)
+            {  double temp = - (double)ipred[i];
+               glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      /* Free working arrays. */
+      xfree(ipred);
+      xfree(ihead);
+      xfree(itail);
+      xfree(iflag);
+      xfree(isup);
+      xfree(lsinks);
+      /* The instance has been successfully generated. */
+      ret = 0;
+done: return ret;
+}
+
+/***********************************************************************
+*  The routine cresup randomly distributes the total supply among the
+*  source nodes. */
+
+static void cresup(struct csa *csa)
+{     int i, j, ks, ksp;
+      xassert(itsup > nsorc);
+      ks = itsup / nsorc;
+      for (i = 1; i <= nsorc; i++)
+         isup[i] = 0;
+      for (i = 1; i <= nsorc; i++)
+      {  ksp = iran(csa, 1, ks);
+         j = iran(csa, 1, nsorc);
+         isup[i] += ksp;
+         isup[j] += ks - ksp;
+      }
+      j = iran(csa, 1, nsorc);
+      isup[j] += itsup - ks * nsorc;
+      return;
+}
+
+/***********************************************************************
+*  The routine chain adds node lpick to the end of the chain with source
+*  node lsorc. */
+
+static void chain(struct csa *csa, int lpick, int lsorc)
+{     int i, j, k, l, m;
+      k = 0;
+      m = ist;
+      for (i = 1; i <= lpick; i++)
+      {  l = k;
+         k = m;
+         m = ipred[k];
+      }
+      ipred[l] = m;
+      j = ipred[lsorc];
+      ipred[k] = j;
+      ipred[lsorc] = k;
+      return;
+}
+
+/***********************************************************************
+*  The routine chnarc puts the arcs in the chain from source lsorc into
+*  the ihead and itail arrays for sorting. */
+
+static void chnarc(struct csa *csa, int lsorc)
+{     int ito, ifrom;
+      nsort = 0;
+      ito = ipred[lsorc];
+L10:  if (ito == lsorc) return;
+      nsort++;
+      ifrom = ipred[ito];
+      ihead[nsort] = ito;
+      itail[nsort] = ifrom;
+      ito = ifrom;
+      goto L10;
+}
+
+/***********************************************************************
+*  The routine sort sorts the nsort arcs in the ihead and itail arrays.
+*  ihead is used as the sort key (i.e. forward star sort order). */
+
+static void sort(struct csa *csa)
+{     int i, j, k, l, m, n, it;
+      n = nsort;
+      m = n;
+L10:  m /= 2;
+      if (m == 0) return;
+      k = n - m;
+      j = 1;
+L20:  i = j;
+L30:  l = i + m;
+      if (itail[i] <= itail[l]) goto L40;
+      it = itail[i];
+      itail[i] = itail[l];
+      itail[l] = it;
+      it = ihead[i];
+      ihead[i] = ihead[l];
+      ihead[l] = it;
+      i -= m;
+      if (i >= 1) goto L30;
+L40:  j++;
+      if (j <= k) goto L20;
+      goto L10;
+}
+
+/***********************************************************************
+*  The routine pickj creates a random number of arcs out of node 'it'.
+*  Various parameters are dynamically adjusted in an attempt to ensure
+*  that the generated network has the correct number of arcs. */
+
+static void pickj(struct csa *csa, int it)
+{     int j, k, l, nn, nupbnd, icap, jcap, icost;
+      if ((nodlft - 1) * 2 > iarcs - narcs - 1)
+      {  nodlft--;
+         return;
+      }
+      if ((iarcs - narcs + nonsor - ktl - 1) / nodlft - nonsor + 1 >= 0)
+         k = nonsor;
+      else
+      {  nupbnd = (iarcs - narcs - nodlft) / nodlft * 2;
+L40:     k = iran(csa, 1, nupbnd);
+         if (nodlft == 1) k = iarcs - narcs;
+         if ((nodlft - 1) * (nonsor - 1) < iarcs - narcs - k) goto L40;
+      }
+      nodlft--;
+      for (j = 1; j <= k; j++)
+      {  nn = iran(csa, 1, ktl);
+         ktl--;
+         for (l = nftsor; l <= nodes; l++)
+         {  if (iflag[l] != 1)
+            {  nn--;
+               if (nn == 0) goto L70;
+            }
+         }
+         return;
+L70:     iflag[l] = 1;
+         icap = itsup;
+         jcap = iran(csa, 1, 100);
+         if (jcap <= ipcap)
+            icap = iran(csa, mincap, maxcap);
+         icost = iran(csa, mincst, maxcst);
+         if (G == NULL)
+            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, l, "", icost,
+               icap);
+         else
+         {  glp_arc *a = glp_add_arc(G, it, l);
+            if (a_cap >= 0)
+            {  double temp = (double)icap;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)icost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+         narcs++;
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine assign generate assignment problems. It defines the unit
+*  supplies, builds a skeleton, then calls pickj to create the arcs. */
+
+static void assign(struct csa *csa)
+{     int i, it, nn, l, ll, icost;
+      if (G == NULL)
+         xprintf("SUPPLY\n");
+      for (i = 1; i <= nsorc; i++)
+      {  isup[i] = 1;
+         iflag[i] = 0;
+         if (G == NULL)
+            xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]);
+         else
+         {  if (v_rhs >= 0)
+            {  double temp = (double)isup[i];
+               glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      if (G == NULL)
+         xprintf("ARCS\n");
+      for (i = nfsink; i <= nodes; i++)
+         ipred[i] = 1;
+      for (it = 1; it <= nsorc; it++)
+      {  for (i = nfsink; i <= nodes; i++)
+            iflag[i] = 0;
+         ktl = nsink - 1;
+         nn = iran(csa, 1, nsink - it + 1);
+         for (l = 1; l <= nsorc; l++)
+         {  if (iflag[l] != 1)
+            {  nn--;
+               if (nn == 0) break;
+            }
+         }
+         narcs++;
+         ll = nsorc + l;
+         icost = iran(csa, mincst, maxcst);
+         if (G == NULL)
+            xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ll, "", icost,
+               isup[1]);
+         else
+         {  glp_arc *a = glp_add_arc(G, it, ll);
+            if (a_cap >= 0)
+            {  double temp = (double)isup[1];
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)icost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+         iflag[l] = 1;
+         iflag[ll] = 1;
+         pickj(csa, it);
+      }
+      return;
+}
+
+/***********************************************************************
+*  Portable congruential (uniform) random number generator:
+*
+*     next_value = ((7**5) * previous_value) modulo ((2**31)-1)
+*
+*  This generator consists of three routines:
+*
+*  (1) setran - initializes constants and seed
+*  (2) iran   - generates an integer random number
+*  (3) rran   - generates a real random number
+*
+*  The generator requires a machine with at least 32 bits of precision.
+*  The seed (iseed) must be in the range [1,(2**31)-1]. */
+
+static void setran(struct csa *csa, int iseed)
+{     xassert(iseed >= 1);
+      mult = 16807;
+      modul = 2147483647;
+      i15 = 1 << 15;
+      i16 = 1 << 16;
+      jran = iseed;
+      return;
+}
+
+/***********************************************************************
+*  The routine iran generates an integer random number between ilow and
+*  ihigh. If ilow > ihigh then iran returns ihigh. */
+
+static int iran(struct csa *csa, int ilow, int ihigh)
+{     int ixhi, ixlo, ixalo, leftlo, ixahi, ifulhi, irtlo, iover,
+         irthi, j;
+      ixhi = jran / i16;
+      ixlo = jran - ixhi * i16;
+      ixalo = ixlo * mult;
+      leftlo = ixalo / i16;
+      ixahi = ixhi * mult;
+      ifulhi = ixahi + leftlo;
+      irtlo = ixalo - leftlo * i16;
+      iover = ifulhi / i15;
+      irthi = ifulhi - iover * i15;
+      jran = ((irtlo - modul) + irthi * i16) + iover;
+      if (jran < 0) jran += modul;
+      j = ihigh - ilow + 1;
+      if (j > 0)
+         return jran % j + ilow;
+      else
+         return ihigh;
+}
+
+/**********************************************************************/
+
+#if 0
+static int scan(char card[80+1], int pos, int len)
+{     char buf[10+1];
+      memcpy(buf, &card[pos-1], len);
+      buf[len] = '\0';
+      return atoi(buf);
+}
+
+int main(void)
+{     int parm[1+15];
+      char card[80+1];
+      xassert(fgets(card, sizeof(card), stdin) == card);
+      parm[1] = scan(card, 1, 8);
+      parm[2] = scan(card, 9, 8);
+      xassert(fgets(card, sizeof(card), stdin) == card);
+      parm[3] = scan(card, 1, 5);
+      parm[4] = scan(card, 6, 5);
+      parm[5] = scan(card, 11, 5);
+      parm[6] = scan(card, 16, 5);
+      parm[7] = scan(card, 21, 5);
+      parm[8] = scan(card, 26, 5);
+      parm[9] = scan(card, 31, 10);
+      parm[10] = scan(card, 41, 5);
+      parm[11] = scan(card, 46, 5);
+      parm[12] = scan(card, 51, 5);
+      parm[13] = scan(card, 56, 5);
+      parm[14] = scan(card, 61, 10);
+      parm[15] = scan(card, 71, 10);
+      glp_netgen(NULL, 0, 0, 0, parm);
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpnet04.c
===================================================================
--- deps/glpk/src/glpnet04.c	(revision 9)
+++ deps/glpk/src/glpnet04.c	(revision 9)
@@ -0,0 +1,768 @@
+/* glpnet04.c (grid-like network problem generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is a modified version of the program GRIDGEN, a grid-like
+*  network problem generator developed by Yusin Lee and Jim Orlin.
+*  The original code is publically available on the DIMACS ftp site at:
+*  <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/gridgen>.
+*
+*  All changes concern only the program interface, so this modified
+*  version produces exactly the same instances as the original version.
+*
+*  Changes were made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_gridgen - grid-like network problem generator
+*
+*  SYNOPSIS
+*
+*  int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost,
+*     const int parm[1+14]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_gridgen is a grid-like network problem generator
+*  developed by Yusin Lee and Jim Orlin.
+*
+*  The parameter G specifies the graph object, to which the generated
+*  problem data have to be stored. Note that on entry the graph object
+*  is erased with the routine glp_erase_graph.
+*
+*  The parameter v_rhs specifies an offset of the field of type double
+*  in the vertex data block, to which the routine stores the supply or
+*  demand value. If v_rhs < 0, the value is not stored.
+*
+*  The parameter a_cap specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the arc capacity.
+*  If a_cap < 0, the capacity is not stored.
+*
+*  The parameter a_cost specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the per-unit cost
+*  if the arc flow. If a_cost < 0, the cost is not stored.
+*
+*  The array parm contains description of the network to be generated:
+*
+*  parm[0]  not used
+*  parm[1]  two-ways arcs indicator:
+*           1 - if links in both direction should be generated
+*           0 - otherwise
+*  parm[2]  random number seed (a positive integer)
+*  parm[3]  number of nodes (the number of nodes generated might be
+*           slightly different to make the network a grid)
+*  parm[4]  grid width
+*  parm[5]  number of sources
+*  parm[6]  number of sinks
+*  parm[7]  average degree
+*  parm[8]  total flow
+*  parm[9]  distribution of arc costs:
+*           1 - uniform
+*           2 - exponential
+*  parm[10] lower bound for arc cost (uniform)
+*           100 * lambda (exponential)
+*  parm[11] upper bound for arc cost (uniform)
+*           not used (exponential)
+*  parm[12] distribution of arc capacities:
+*           1 - uniform
+*           2 - exponential
+*  parm[13] lower bound for arc capacity (uniform)
+*           100 * lambda (exponential)
+*  parm[14] upper bound for arc capacity (uniform)
+*           not used (exponential)
+*
+*  RETURNS
+*
+*  If the instance was successfully generated, the routine glp_gridgen
+*  returns zero; otherwise, if specified parameters are inconsistent,
+*  the routine returns a non-zero error code.
+*
+*  COMMENTS
+*
+*  This network generator generates a grid-like network plus a super
+*  node. In additional to the arcs connecting the nodes in the grid,
+*  there is an arc from each supply node to the super node and from the
+*  super node to each demand node to guarantee feasiblity. These arcs
+*  have very high costs and very big capacities.
+*
+*  The idea of this network generator is as follows: First, a grid of
+*  n1 * n2 is generated. For example, 5 * 3. The nodes are numbered as
+*  1 to 15, and the supernode is numbered as n1*n2+1. Then arcs between
+*  adjacent nodes are generated. For these arcs, the user is allowed to
+*  specify either to generate two-way arcs or one-way arcs. If two-way
+*  arcs are to be generated, two arcs, one in each direction, will be
+*  generated between each adjacent node pairs. Otherwise, only one arc
+*  will be generated. If this is the case, the arcs will be generated
+*  in alterntive directions as shown below.
+*
+*      1 ---> 2 ---> 3 ---> 4 ---> 5
+*      |      ^      |      ^      |
+*      |      |      |      |      |
+*      V      |      V      |      V
+*      6 <--- 7 <--- 8 <--- 9 <--- 10
+*      |      ^      |      ^      |
+*      |      |      |      |      |
+*      V      |      V      |      V
+*     11 --->12 --->13 --->14 ---> 15
+*
+*  Then the arcs between the super node and the source/sink nodes are
+*  added as mentioned before. If the number of arcs still doesn't reach
+*  the requirement, additional arcs will be added by uniformly picking
+*  random node pairs. There is no checking to prevent multiple arcs
+*  between any pair of nodes. However, there will be no self-arcs (arcs
+*  that poins back to its tail node) in the network.
+*
+*  The source and sink nodes are selected uniformly in the network, and
+*  the imbalances of each source/sink node are also assigned by uniform
+*  distribution. */
+
+struct stat_para
+{     /* structure for statistical distributions */
+      int distribution;
+      /* the distribution: */
+#define UNIFORM      1  /* uniform distribution */
+#define EXPONENTIAL  2  /* exponential distribution */
+      double parameter[5];
+      /* the parameters of the distribution */
+};
+
+struct arcs
+{     int from;
+      /* the FROM node of that arc */
+      int to;
+      /* the TO node of that arc */
+      int cost;
+      /* original cost of that arc */
+      int u;
+      /* capacity of the arc */
+};
+
+struct imbalance
+{     int node;
+      /* Node ID */
+      int supply;
+      /* Supply of that node */
+};
+
+struct csa
+{     /* common storage area */
+      glp_graph *G;
+      int v_rhs, a_cap, a_cost;
+      int seed;
+      /* random number seed */
+      int seed_original;
+      /* the original seed from input */
+      int two_way;
+      /* 0: generate arcs in both direction for the basic grid, except
+         for the arcs to/from the super node.  1: o/w */
+      int n_node;
+      /* total number of nodes in the network, numbered 1 to n_node,
+         including the super node, which is the last one */
+      int n_arc;
+      /* total number of arcs in the network, counting EVERY arc. */
+      int n_grid_arc;
+      /* number of arcs in the basic grid, including the arcs to/from
+         the super node */
+      int n_source, n_sink;
+      /* number of source and sink nodes */
+      int avg_degree;
+      /* average degree, arcs to and from the super node are counted */
+      int t_supply;
+      /* total supply in the network */
+      int n1, n2;
+      /* the two edges of the network grid.  n1 >= n2 */
+      struct imbalance *source_list, *sink_list;
+      /* head of the array of source/sink nodes */
+      struct stat_para arc_costs;
+      /* the distribution of arc costs */
+      struct stat_para capacities;
+      /* distribution of the capacities of the arcs */
+      struct arcs *arc_list;
+      /* head of the arc list array.  Arcs in this array are in the
+         order of grid_arcs, arcs to/from super node, and other arcs */
+};
+
+#define G (csa->G)
+#define v_rhs (csa->v_rhs)
+#define a_cap (csa->a_cap)
+#define a_cost (csa->a_cost)
+#define seed (csa->seed)
+#define seed_original (csa->seed_original)
+#define two_way (csa->two_way)
+#define n_node (csa->n_node)
+#define n_arc (csa->n_arc)
+#define n_grid_arc (csa->n_grid_arc)
+#define n_source (csa->n_source)
+#define n_sink (csa->n_sink)
+#define avg_degree (csa->avg_degree)
+#define t_supply (csa->t_supply)
+#define n1 (csa->n1)
+#define n2 (csa->n2)
+#define source_list (csa->source_list)
+#define sink_list (csa->sink_list)
+#define arc_costs (csa->arc_costs)
+#define capacities (csa->capacities)
+#define arc_list (csa->arc_list)
+
+static void assign_capacities(struct csa *csa);
+static void assign_costs(struct csa *csa);
+static void assign_imbalance(struct csa *csa);
+static int exponential(struct csa *csa, double lambda[1]);
+static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
+      *arc_ptr);
+static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
+      *arc_ptr);
+static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr);
+static void generate(struct csa *csa);
+static void output(struct csa *csa);
+static double randy(struct csa *csa);
+static void select_source_sinks(struct csa *csa);
+static int uniform(struct csa *csa, double a[2]);
+
+int glp_gridgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost,
+      const int parm[1+14])
+{     struct csa _csa, *csa = &_csa;
+      int n, ret;
+      G = G_;
+      v_rhs = _v_rhs;
+      a_cap = _a_cap;
+      a_cost = _a_cost;
+      if (G != NULL)
+      {  if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double))
+            xerror("glp_gridgen: v_rhs = %d; invalid offset\n", v_rhs);
+         if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+            xerror("glp_gridgen: a_cap = %d; invalid offset\n", a_cap);
+         if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double))
+            xerror("glp_gridgen: a_cost = %d; invalid offset\n", a_cost)
+               ;
+      }
+      /* Check the parameters for consistency. */
+      if (!(parm[1] == 0 || parm[1] == 1))
+      {  ret = 1;
+         goto done;
+      }
+      if (parm[2] < 1)
+      {  ret = 2;
+         goto done;
+      }
+      if (!(10 <= parm[3] && parm[3] <= 40000))
+      {  ret = 3;
+         goto done;
+      }
+      if (!(1 <= parm[4] && parm[4] <= 40000))
+      {  ret = 4;
+         goto done;
+      }
+      if (!(parm[5] >= 0 && parm[6] >= 0 && parm[5] + parm[6] <=
+         parm[3]))
+      {  ret = 5;
+         goto done;
+      }
+      if (!(1 <= parm[7] && parm[7] <= parm[3]))
+      {  ret = 6;
+         goto done;
+      }
+      if (parm[8] < 0)
+      {  ret = 7;
+         goto done;
+      }
+      if (!(parm[9] == 1 || parm[9] == 2))
+      {  ret = 8;
+         goto done;
+      }
+      if (parm[9] == 1 && parm[10] > parm[11] ||
+          parm[9] == 2 && parm[10] < 1)
+      {  ret = 9;
+         goto done;
+      }
+      if (!(parm[12] == 1 || parm[12] == 2))
+      {  ret = 10;
+         goto done;
+      }
+      if (parm[12] == 1 && !(0 <= parm[13] && parm[13] <= parm[14]) ||
+          parm[12] == 2 && parm[13] < 1)
+      {  ret = 11;
+         goto done;
+      }
+      /* Initialize the graph object. */
+      if (G != NULL)
+      {  glp_erase_graph(G, G->v_size, G->a_size);
+         glp_set_graph_name(G, "GRIDGEN");
+      }
+      /* Copy the generator parameters. */
+      two_way = parm[1];
+      seed_original = seed = parm[2];
+      n_node = parm[3];
+      n = parm[4];
+      n_source = parm[5];
+      n_sink = parm[6];
+      avg_degree = parm[7];
+      t_supply = parm[8];
+      arc_costs.distribution = parm[9];
+      if (parm[9] == 1)
+      {  arc_costs.parameter[0] = parm[10];
+         arc_costs.parameter[1] = parm[11];
+      }
+      else
+      {  arc_costs.parameter[0] = (double)parm[10] / 100.0;
+         arc_costs.parameter[1] = 0.0;
+      }
+      capacities.distribution = parm[12];
+      if (parm[12] == 1)
+      {  capacities.parameter[0] = parm[13];
+         capacities.parameter[1] = parm[14];
+      }
+      else
+      {  capacities.parameter[0] = (double)parm[13] / 100.0;
+         capacities.parameter[1] = 0.0;
+      }
+      /* Calculate the edge lengths of the grid according to the
+         input. */
+      if (n * n >= n_node)
+      {  n1 = n;
+         n2 = (int)((double)n_node / (double)n + 0.5);
+      }
+      else
+      {  n2 = n;
+         n1 = (int)((double)n_node / (double)n + 0.5);
+      }
+      /* Recalculate the total number of nodes and plus 1 for the super
+         node. */
+      n_node = n1 * n2 + 1;
+      n_arc = n_node * avg_degree;
+      n_grid_arc = (two_way + 1) * ((n1 - 1) * n2 + (n2 - 1) * n1) +
+         n_source + n_sink;
+      if (n_grid_arc > n_arc) n_arc = n_grid_arc;
+      arc_list = xcalloc(n_arc, sizeof(struct arcs));
+      source_list = xcalloc(n_source, sizeof(struct imbalance));
+      sink_list = xcalloc(n_sink, sizeof(struct imbalance));
+      /* Generate a random network. */
+      generate(csa);
+      /* Output the network. */
+      output(csa);
+      /* Free all allocated memory. */
+      xfree(arc_list);
+      xfree(source_list);
+      xfree(sink_list);
+      /* The instance has been successfully generated. */
+      ret = 0;
+done: return ret;
+}
+
+#undef random
+
+static void assign_capacities(struct csa *csa)
+{     /* Assign a capacity to each arc. */
+      struct arcs *arc_ptr = arc_list;
+      int (*random)(struct csa *csa, double *);
+      int i;
+      /* Determine the random number generator to use. */
+      switch (arc_costs.distribution)
+      {  case UNIFORM:
+            random = uniform;
+            break;
+         case EXPONENTIAL:
+            random = exponential;
+            break;
+         default:
+            xassert(csa != csa);
+      }
+      /* Assign capacities to grid arcs. */
+      for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
+         arc_ptr->u = random(csa, capacities.parameter);
+      i = i - n_source - n_sink;
+      /* Assign capacities to arcs to/from supernode. */
+      for (; i < n_grid_arc; i++, arc_ptr++)
+         arc_ptr->u = t_supply;
+      /* Assign capacities to all other arcs. */
+      for (; i < n_arc; i++, arc_ptr++)
+         arc_ptr->u = random(csa, capacities.parameter);
+      return;
+}
+
+static void assign_costs(struct csa *csa)
+{     /* Assign a cost to each arc. */
+      struct arcs *arc_ptr = arc_list;
+      int (*random)(struct csa *csa, double *);
+      int i;
+      /* A high cost assigned to arcs to/from the supernode. */
+      int high_cost;
+      /* The maximum cost assigned to arcs in the base grid. */
+      int max_cost = 0;
+      /* Determine the random number generator to use. */
+      switch (arc_costs.distribution)
+      {  case UNIFORM:
+            random = uniform;
+            break;
+         case EXPONENTIAL:
+            random = exponential;
+            break;
+         default:
+            xassert(csa != csa);
+      }
+      /* Assign costs to arcs in the base grid. */
+      for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++)
+      {  arc_ptr->cost = random(csa, arc_costs.parameter);
+         if (max_cost < arc_ptr->cost) max_cost = arc_ptr->cost;
+      }
+      i = i - n_source - n_sink;
+      /* Assign costs to arcs to/from the super node. */
+      high_cost = max_cost * 2;
+      for (; i < n_grid_arc; i++, arc_ptr++)
+         arc_ptr->cost = high_cost;
+      /* Assign costs to all other arcs. */
+      for (; i < n_arc; i++, arc_ptr++)
+         arc_ptr->cost = random(csa, arc_costs.parameter);
+      return;
+}
+
+static void assign_imbalance(struct csa *csa)
+{     /* Assign an imbalance to each node. */
+      int total, i;
+      double avg;
+      struct imbalance *ptr;
+      /* assign the supply nodes */
+      avg = 2.0 * t_supply / n_source;
+      do
+      {  for (i = 1, total = t_supply, ptr = source_list + 1;
+            i < n_source; i++, ptr++)
+         {  ptr->supply = (int)(randy(csa) * avg + 0.5);
+            total -= ptr->supply;
+         }
+         source_list->supply = total;
+      }
+      /* redo all if the assignment "overshooted" */
+      while (total <= 0);
+      /* assign the demand nodes */
+      avg = -2.0 * t_supply / n_sink;
+      do
+      {  for (i = 1, total = t_supply, ptr = sink_list + 1;
+            i < n_sink; i++, ptr++)
+         {  ptr->supply = (int)(randy(csa) * avg - 0.5);
+            total += ptr->supply;
+         }
+         sink_list->supply = - total;
+      }
+      while (total <= 0);
+      return;
+}
+
+static int exponential(struct csa *csa, double lambda[1])
+{     /* Returns an "exponentially distributed" integer with parameter
+         lambda. */
+      return ((int)(- lambda[0] * log((double)randy(csa)) + 0.5));
+}
+
+static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs
+      *arc_ptr)
+{     /* Generate an arc from each source to the supernode and from
+         supernode to each sink. */
+      int i;
+      for (i = 0; i < n_source; i++, arc_ptr++)
+      {  arc_ptr->from = source_list[i].node;
+         arc_ptr->to = n_node;
+      }
+      for (i = 0; i < n_sink; i++, arc_ptr++)
+      {  arc_ptr->to = sink_list[i].node;
+         arc_ptr->from = n_node;
+      }
+      return arc_ptr;
+}
+
+static struct arcs *gen_basic_grid(struct csa *csa, struct arcs
+      *arc_ptr)
+{     /* Generate the basic grid. */
+      int direction = 1, i, j, k;
+      if (two_way)
+      {  /* Generate an arc in each direction. */
+         for (i = 1; i < n_node; i += n1)
+         {  for (j = i, k = j + n1 - 1; j < k; j++)
+            {  arc_ptr->from = j;
+               arc_ptr->to = j + 1;
+               arc_ptr++;
+               arc_ptr->from = j + 1;
+               arc_ptr->to = j;
+               arc_ptr++;
+            }
+         }
+         for (i = 1; i <= n1; i++)
+         {  for (j = i + n1; j < n_node; j += n1)
+            {  arc_ptr->from = j;
+               arc_ptr->to = j - n1;
+               arc_ptr++;
+               arc_ptr->from = j - n1;
+               arc_ptr->to = j;
+               arc_ptr++;
+            }
+         }
+      }
+      else
+      {  /* Generate one arc in each direction. */
+         for (i = 1; i < n_node; i += n1)
+         {  if (direction == 1)
+               j = i;
+            else
+               j = i + 1;
+            for (k = j + n1 - 1; j < k; j++)
+            {  arc_ptr->from = j;
+               arc_ptr->to = j + direction;
+               arc_ptr++;
+            }
+            direction = - direction;
+         }
+         for (i = 1; i <= n1; i++)
+         {  j = i + n1;
+            if (direction == 1)
+            {  for (; j < n_node; j += n1)
+               {  arc_ptr->from = j - n1;
+                  arc_ptr->to = j;
+                  arc_ptr++;
+               }
+            }
+            else
+            {  for (; j < n_node; j += n1)
+               {  arc_ptr->from = j - n1;
+                  arc_ptr->to = j;
+                  arc_ptr++;
+               }
+            }
+            direction = - direction;
+         }
+      }
+      return arc_ptr;
+}
+
+static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr)
+{     /* Generate random arcs to meet the specified density. */
+      int i;
+      double ab[2];
+      ab[0] = 0.9;
+      ab[1] = n_node - 0.99;  /* upper limit is n_node-1 because the
+                                 supernode cannot be selected */
+      for (i = n_grid_arc; i < n_arc; i++, arc_ptr++)
+      {  arc_ptr->from = uniform(csa, ab);
+         arc_ptr->to = uniform(csa, ab);
+         if (arc_ptr->from == arc_ptr->to)
+         {  arc_ptr--;
+            i--;
+         }
+      }
+      return;
+}
+
+static void generate(struct csa *csa)
+{     /* Generate a random network. */
+      struct arcs *arc_ptr = arc_list;
+      arc_ptr = gen_basic_grid(csa, arc_ptr);
+      select_source_sinks(csa);
+      arc_ptr = gen_additional_arcs(csa, arc_ptr);
+      gen_more_arcs(csa, arc_ptr);
+      assign_costs(csa);
+      assign_capacities(csa);
+      assign_imbalance(csa);
+      return;
+}
+
+static void output(struct csa *csa)
+{     /* Output the network in DIMACS format. */
+      struct arcs *arc_ptr;
+      struct imbalance *imb_ptr;
+      int i;
+      if (G != NULL) goto skip;
+      /* Output "c", "p" records. */
+      xprintf("c generated by GRIDGEN\n");
+      xprintf("c seed %d\n", seed_original);
+      xprintf("c nodes %d\n", n_node);
+      xprintf("c grid size %d X %d\n", n1, n2);
+      xprintf("c sources %d sinks %d\n", n_source, n_sink);
+      xprintf("c avg. degree %d\n", avg_degree);
+      xprintf("c supply %d\n", t_supply);
+      switch (arc_costs.distribution)
+      {  case UNIFORM:
+            xprintf("c arc costs: UNIFORM distr. min %d max %d\n",
+               (int)arc_costs.parameter[0],
+               (int)arc_costs.parameter[1]);
+            break;
+         case EXPONENTIAL:
+            xprintf("c arc costs: EXPONENTIAL distr. lambda %d\n",
+               (int)arc_costs.parameter[0]);
+            break;
+         default:
+            xassert(csa != csa);
+      }
+      switch (capacities.distribution)
+      {  case UNIFORM:
+            xprintf("c arc caps :  UNIFORM distr. min %d max %d\n",
+               (int)capacities.parameter[0],
+               (int)capacities.parameter[1]);
+            break;
+         case EXPONENTIAL:
+            xprintf("c arc caps :  EXPONENTIAL distr. %d lambda %d\n",
+               (int)capacities.parameter[0]);
+            break;
+         default:
+            xassert(csa != csa);
+      }
+skip: if (G == NULL)
+         xprintf("p min %d %d\n", n_node, n_arc);
+      else
+      {  glp_add_vertices(G, n_node);
+         if (v_rhs >= 0)
+         {  double zero = 0.0;
+            for (i = 1; i <= n_node; i++)
+            {  glp_vertex *v = G->v[i];
+               memcpy((char *)v->data + v_rhs, &zero, sizeof(double));
+            }
+         }
+      }
+      /* Output "n node supply". */
+      for (i = 0, imb_ptr = source_list; i < n_source; i++, imb_ptr++)
+      {  if (G == NULL)
+            xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
+         else
+         {  if (v_rhs >= 0)
+            {  double temp = (double)imb_ptr->supply;
+               glp_vertex *v = G->v[imb_ptr->node];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      for (i = 0, imb_ptr = sink_list; i < n_sink; i++, imb_ptr++)
+      {  if (G == NULL)
+            xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply);
+         else
+         {  if (v_rhs >= 0)
+            {  double temp = (double)imb_ptr->supply;
+               glp_vertex *v = G->v[imb_ptr->node];
+               memcpy((char *)v->data + v_rhs, &temp, sizeof(double));
+            }
+         }
+      }
+      /* Output "a from to lowcap=0 hicap cost". */
+      for (i = 0, arc_ptr = arc_list; i < n_arc; i++, arc_ptr++)
+      {  if (G == NULL)
+            xprintf("a %d %d 0 %d %d\n", arc_ptr->from, arc_ptr->to,
+               arc_ptr->u, arc_ptr->cost);
+         else
+         {  glp_arc *a = glp_add_arc(G, arc_ptr->from, arc_ptr->to);
+            if (a_cap >= 0)
+            {  double temp = (double)arc_ptr->u;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+            if (a_cost >= 0)
+            {  double temp = (double)arc_ptr->cost;
+               memcpy((char *)a->data + a_cost, &temp, sizeof(double));
+            }
+         }
+      }
+      return;
+}
+
+static double randy(struct csa *csa)
+{     /* Returns a random number between 0.0 and 1.0.
+         See Ward Cheney & David Kincaid, "Numerical Mathematics and
+         Computing," 2Ed, pp. 335. */
+      seed = 16807 * seed % 2147483647;
+      if (seed < 0) seed = - seed;
+      return seed * 4.6566128752459e-10;
+}
+
+static void select_source_sinks(struct csa *csa)
+{     /* Randomly select the source nodes and sink nodes. */
+      int i, *int_ptr;
+      int *temp_list;   /* a temporary list of nodes */
+      struct imbalance *ptr;
+      double ab[2];     /* parameter for random number generator */
+      ab[0] = 0.9;
+      ab[1] = n_node - 0.99;  /* upper limit is n_node-1 because the
+                                 supernode cannot be selected */
+      temp_list = xcalloc(n_node, sizeof(int));
+      for (i = 0, int_ptr = temp_list; i < n_node; i++, int_ptr++)
+         *int_ptr = 0;
+      /* Select the source nodes. */
+      for (i = 0, ptr = source_list; i < n_source; i++, ptr++)
+      {  ptr->node = uniform(csa, ab);
+         if (temp_list[ptr->node] == 1) /* check for duplicates */
+         {  ptr--;
+            i--;
+         }
+         else
+            temp_list[ptr->node] = 1;
+      }
+      /* Select the sink nodes. */
+      for (i = 0, ptr = sink_list; i < n_sink; i++, ptr++)
+      {  ptr->node = uniform(csa, ab);
+         if (temp_list[ptr->node] == 1)
+         {  ptr--;
+            i--;
+         }
+         else
+            temp_list[ptr->node] = 1;
+      }
+      xfree(temp_list);
+      return;
+}
+
+int uniform(struct csa *csa, double a[2])
+{     /* Generates an integer uniformly selected from [a[0],a[1]]. */
+      return (int)((a[1] - a[0]) * randy(csa) + a[0] + 0.5);
+}
+
+/**********************************************************************/
+
+#if 0
+int main(void)
+{     int parm[1+14];
+      double temp;
+      scanf("%d", &parm[1]);
+      scanf("%d", &parm[2]);
+      scanf("%d", &parm[3]);
+      scanf("%d", &parm[4]);
+      scanf("%d", &parm[5]);
+      scanf("%d", &parm[6]);
+      scanf("%d", &parm[7]);
+      scanf("%d", &parm[8]);
+      scanf("%d", &parm[9]);
+      if (parm[9] == 1)
+      {  scanf("%d", &parm[10]);
+         scanf("%d", &parm[11]);
+      }
+      else
+      {  scanf("%le", &temp);
+         parm[10] = (int)(100.0 * temp + .5);
+         parm[11] = 0;
+      }
+      scanf("%d", &parm[12]);
+      if (parm[12] == 1)
+      {  scanf("%d", &parm[13]);
+         scanf("%d", &parm[14]);
+      }
+      else
+      {  scanf("%le", &temp);
+         parm[13] = (int)(100.0 * temp + .5);
+         parm[14] = 0;
+      }
+      glp_gridgen(NULL, 0, 0, 0, parm);
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpnet05.c
===================================================================
--- deps/glpk/src/glpnet05.c	(revision 9)
+++ deps/glpk/src/glpnet05.c	(revision 9)
@@ -0,0 +1,367 @@
+/* glpnet05.c (Goldfarb's maximum flow problem generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is a modified version of the program RMFGEN, a maxflow
+*  problem generator developed by D.Goldfarb and M.Grigoriadis, and
+*  originally implemented by Tamas Badics <badics@rutcor.rutgers.edu>.
+*  The original code is publically available on the DIMACS ftp site at:
+*  <ftp://dimacs.rutgers.edu/pub/netflow/generators/network/genrmf>.
+*
+*  All changes concern only the program interface, so this modified
+*  version produces exactly the same instances as the original version.
+*
+*  Changes were made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glprng.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_rmfgen - Goldfarb's maximum flow problem generator
+*
+*  SYNOPSIS
+*
+*  int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap,
+*     const int parm[1+5]);
+*
+*  DESCRIPTION
+*
+*  The routine glp_rmfgen is a maximum flow problem generator developed
+*  by D.Goldfarb and M.Grigoriadis.
+*
+*  The parameter G specifies the graph object, to which the generated
+*  problem data have to be stored. Note that on entry the graph object
+*  is erased with the routine glp_erase_graph.
+*
+*  The pointer s specifies a location, to which the routine stores the
+*  source node number. If s is NULL, the node number is not stored.
+*
+*  The pointer t specifies a location, to which the routine stores the
+*  sink node number. If t is NULL, the node number is not stored.
+*
+*  The parameter a_cap specifies an offset of the field of type double
+*  in the arc data block, to which the routine stores the arc capacity.
+*  If a_cap < 0, the capacity is not stored.
+*
+*  The array parm contains description of the network to be generated:
+*
+*  parm[0]  not used
+*  parm[1]  (seed)   random number seed (a positive integer)
+*  parm[2]  (a)      frame size
+*  parm[3]  (b)      depth
+*  parm[4]  (c1)     minimal arc capacity
+*  parm[5]  (c2)     maximal arc capacity
+*
+*  RETURNS
+*
+*  If the instance was successfully generated, the routine glp_netgen
+*  returns zero; otherwise, if specified parameters are inconsistent,
+*  the routine returns a non-zero error code.
+*
+*  COMMENTS
+*
+*  The generated network is as follows. It has b pieces of frames of
+*  size a * a. (So alltogether the number of vertices is a * a * b)
+*
+*  In each frame all the vertices are connected with their neighbours
+*  (forth and back). In addition the vertices of a frame are connected
+*  one to one with the vertices of next frame using a random permutation
+*  of those vertices.
+*
+*  The source is the lower left vertex of the first frame, the sink is
+*  the upper right vertex of the b'th frame.
+*
+*                    t
+*           +-------+
+*           |      .|
+*           |     . |
+*        /  |    /  |
+*       +-------+/ -+ b
+*       |    |  |/.
+*     a |   -v- |/
+*       |    |  |/
+*       +-------+ 1
+*      s    a
+*
+*  The capacities are randomly chosen integers from the range of [c1,c2]
+*  in the case of interconnecting edges, and c2 * a * a for the in-frame
+*  edges.
+*
+*  REFERENCES
+*
+*  D.Goldfarb and M.D.Grigoriadis, "A computational comparison of the
+*  Dinic and network simplex methods for maximum flow." Annals of Op.
+*  Res. 13 (1988), pp. 83-123.
+*
+*  U.Derigs and W.Meier, "Implementing Goldberg's max-flow algorithm:
+*  A computational investigation." Zeitschrift fuer Operations Research
+*  33 (1989), pp. 383-403. */
+
+typedef struct VERTEX
+{     struct EDGE **edgelist;
+      /* Pointer to the list of pointers to the adjacent edges.
+         (No matter that to or from edges) */
+      struct EDGE **current;
+      /* Pointer to the current edge */
+      int degree;
+      /* Number of adjacent edges (both direction) */
+      int index;
+} vertex;
+
+typedef struct EDGE
+{     int from;
+      int to;
+      int cap;
+      /* Capacity */
+} edge;
+
+typedef struct NETWORK
+{     struct NETWORK *next, *prev;
+      int vertnum;
+      int edgenum;
+      vertex *verts;
+      /* Vertex array[1..vertnum] */
+      edge *edges;
+      /* Edge array[1..edgenum] */
+      int source;
+      /* Pointer to the source */
+      int sink;
+      /* Pointer to the sink */
+} network;
+
+struct csa
+{     /* common storage area */
+      glp_graph *G;
+      int *s, *t, a_cap;
+      RNG *rand;
+      network *N;
+      int *Parr;
+      int A, AA, C2AA, Ec;
+};
+
+#define G      (csa->G)
+#define s      (csa->s)
+#define t      (csa->t)
+#define a_cap  (csa->a_cap)
+#define N      (csa->N)
+#define Parr   (csa->Parr)
+#define A      (csa->A)
+#define AA     (csa->AA)
+#define C2AA   (csa->C2AA)
+#define Ec     (csa->Ec)
+
+#undef random
+#define random(A) (int)(rng_unif_01(csa->rand) * (double)(A))
+#define RANDOM(A, B) (int)(random((B) - (A) + 1) + (A))
+#define sgn(A) (((A) > 0) ? 1 : ((A) == 0) ? 0 : -1)
+
+static void make_edge(struct csa *csa, int from, int to, int c1, int c2)
+{     Ec++;
+      N->edges[Ec].from = from;
+      N->edges[Ec].to = to;
+      N->edges[Ec].cap = RANDOM(c1, c2);
+      return;
+}
+
+static void permute(struct csa *csa)
+{     int i, j, tmp;
+      for (i = 1; i < AA; i++)
+      {  j = RANDOM(i, AA);
+         tmp = Parr[i];
+         Parr[i] = Parr[j];
+         Parr[j] = tmp;
+      }
+      return;
+}
+
+static void connect(struct csa *csa, int offset, int cv, int x1, int y1)
+{     int cv1;
+      cv1 = offset + (x1 - 1) * A + y1;
+      Ec++;
+      N->edges[Ec].from = cv;
+      N->edges[Ec].to = cv1;
+      N->edges[Ec].cap = C2AA;
+      return;
+}
+
+static network *gen_rmf(struct csa *csa, int a, int b, int c1, int c2)
+{     /* generates a network with a*a*b nodes and 6a*a*b-4ab-2a*a edges
+         random_frame network:
+         Derigs & Meier, Methods & Models of OR (1989), 33:383-403 */
+      int x, y, z, offset, cv;
+      A = a;
+      AA = a * a;
+      C2AA = c2 * AA;
+      Ec = 0;
+      N = (network *)xmalloc(sizeof(network));
+      N->vertnum = AA * b;
+      N->edgenum = 5 * AA * b - 4 * A * b - AA;
+      N->edges = (edge *)xcalloc(N->edgenum + 1, sizeof(edge));
+      N->source = 1;
+      N->sink = N->vertnum;
+      Parr = (int *)xcalloc(AA + 1, sizeof(int));
+      for (x = 1; x <= AA; x++)
+         Parr[x] = x;
+      for (z = 1; z <= b; z++)
+      {  offset = AA * (z - 1);
+         if (z != b)
+            permute(csa);
+         for (x = 1; x <= A; x++)
+         {  for (y = 1; y <= A; y++)
+            {  cv = offset + (x - 1) * A + y;
+               if (z != b)
+                  make_edge(csa, cv, offset + AA + Parr[cv - offset],
+                     c1, c2); /* the intermediate edges */
+               if (y < A)
+                  connect(csa, offset, cv, x, y + 1);
+               if (y > 1)
+                  connect(csa, offset, cv, x, y - 1);
+               if (x < A)
+                  connect(csa, offset, cv, x + 1, y);
+               if (x > 1)
+                  connect(csa, offset, cv, x - 1, y);
+            }
+         }
+      }
+      xfree(Parr);
+      return N;
+}
+
+static void print_max_format(struct csa *csa, network *n, char *comm[],
+      int dim)
+{     /* prints a network heading with dim lines of comments (no \n
+         needs at the ends) */
+      int i, vnum, e_num;
+      edge *e;
+      vnum = n->vertnum;
+      e_num = n->edgenum;
+      if (G == NULL)
+      {  for (i = 0; i < dim; i++)
+            xprintf("c %s\n", comm[i]);
+         xprintf("p max %7d %10d\n", vnum, e_num);
+         xprintf("n %7d s\n", n->source);
+         xprintf("n %7d t\n", n->sink);
+      }
+      else
+      {  glp_add_vertices(G, vnum);
+         if (s != NULL) *s = n->source;
+         if (t != NULL) *t = n->sink;
+      }
+      for (i = 1; i <= e_num; i++)
+      {  e = &n->edges[i];
+         if (G == NULL)
+            xprintf("a %7d %7d %10d\n", e->from, e->to, (int)e->cap);
+         else
+         {  glp_arc *a = glp_add_arc(G, e->from, e->to);
+            if (a_cap >= 0)
+            {  double temp = (double)e->cap;
+               memcpy((char *)a->data + a_cap, &temp, sizeof(double));
+            }
+         }
+      }
+      return;
+}
+
+static void gen_free_net(network *n)
+{     xfree(n->edges);
+      xfree(n);
+      return;
+}
+
+int glp_rmfgen(glp_graph *G_, int *_s, int *_t, int _a_cap,
+      const int parm[1+5])
+{     struct csa _csa, *csa = &_csa;
+      network *n;
+      char comm[10][80], *com1[10];
+      int seed, a, b, c1, c2, ret;
+      G = G_;
+      s = _s;
+      t = _t;
+      a_cap = _a_cap;
+      if (G != NULL)
+      {  if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double))
+           xerror("glp_rmfgen: a_cap = %d; invalid offset\n", a_cap);
+      }
+      seed = parm[1];
+      a = parm[2];
+      b = parm[3];
+      c1 = parm[4];
+      c2 = parm[5];
+      if (!(seed > 0 && 1 <= a && a <= 1000 && 1 <= b && b <= 1000 &&
+            0 <= c1 && c1 <= c2 && c2 <= 1000))
+      {  ret = 1;
+         goto done;
+      }
+      if (G != NULL)
+      {  glp_erase_graph(G, G->v_size, G->a_size);
+         glp_set_graph_name(G, "RMFGEN");
+      }
+      csa->rand = rng_create_rand();
+      rng_init_rand(csa->rand, seed);
+      n = gen_rmf(csa, a, b, c1, c2);
+      sprintf(comm[0], "This file was generated by genrmf.");
+      sprintf(comm[1], "The parameters are: a: %d b: %d c1: %d c2: %d",
+         a, b, c1, c2);
+      com1[0] = comm[0];
+      com1[1] = comm[1];
+      print_max_format(csa, n, com1, 2);
+      gen_free_net(n);
+      rng_delete_rand(csa->rand);
+      ret = 0;
+done: return ret;
+}
+
+/**********************************************************************/
+
+#if 0
+int main(int argc, char *argv[])
+{     int seed, a, b, c1, c2, i, parm[1+5];
+      seed = 123;
+      a = b = c1 = c2 = -1;
+      for (i = 1; i < argc; i++)
+      {  if (strcmp(argv[i], "-seed") == 0)
+            seed = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-a") == 0)
+            a = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-b") == 0)
+            b = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-c1") == 0)
+            c1 = atoi(argv[++i]);
+         else if (strcmp(argv[i], "-c2") == 0)
+            c2 = atoi(argv[++i]);
+      }
+      if (a < 0 || b < 0 || c1 < 0 || c2 < 0)
+      {  xprintf("Usage:\n");
+         xprintf("genrmf [-seed seed] -a frame_size -b depth\n");
+         xprintf("        -c1 cap_range1 -c2 cap_range2\n");
+      }
+      else
+      {  parm[1] = seed;
+         parm[2] = a;
+         parm[3] = b;
+         parm[4] = c1;
+         parm[5] = c2;
+         glp_rmfgen(NULL, NULL, NULL, 0, parm);
+      }
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glpnet06.c
===================================================================
--- deps/glpk/src/glpnet06.c	(revision 9)
+++ deps/glpk/src/glpnet06.c	(revision 9)
@@ -0,0 +1,383 @@
+/* glpnet06.c (out-of-kilter algorithm) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  okalg - out-of-kilter algorithm
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int okalg(int nv, int na, const int tail[], const int head[],
+*     const int low[], const int cap[], const int cost[], int x[],
+*     int pi[]);
+*
+*  DESCRIPTION
+*
+*  The routine okalg implements the out-of-kilter algorithm to find a
+*  minimal-cost circulation in the specified flow network.
+*
+*  INPUT PARAMETERS
+*
+*  nv is the number of nodes, nv >= 0.
+*
+*  na is the number of arcs, na >= 0.
+*
+*  tail[a], a = 1,...,na, is the index of tail node of arc a.
+*
+*  head[a], a = 1,...,na, is the index of head node of arc a.
+*
+*  low[a], a = 1,...,na, is an lower bound to the flow through arc a.
+*
+*  cap[a], a = 1,...,na, is an upper bound to the flow through arc a,
+*  which is the capacity of the arc.
+*
+*  cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a.
+*
+*  NOTES
+*
+*  1. Multiple arcs are allowed, but self-loops are not allowed.
+*
+*  2. It is required that 0 <= low[a] <= cap[a] for all arcs.
+*
+*  3. Arc costs may have any sign.
+*
+*  OUTPUT PARAMETERS
+*
+*  x[a], a = 1,...,na, is optimal value of the flow through arc a.
+*
+*  pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation
+*  equality constraint corresponding to node i (the node potential).
+*
+*  RETURNS
+*
+*  0  optimal circulation found;
+*
+*  1  there is no feasible circulation;
+*
+*  2  integer overflow occured;
+*
+*  3  optimality test failed (logic error).
+*
+*  REFERENCES
+*
+*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
+*  Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow
+*  Problems," pp.113-26. */
+
+static int overflow(int u, int v)
+{     /* check for integer overflow on computing u + v */
+      if (u > 0 && v > 0 && u + v < 0) return 1;
+      if (u < 0 && v < 0 && u + v > 0) return 1;
+      return 0;
+}
+
+int okalg(int nv, int na, const int tail[], const int head[],
+      const int low[], const int cap[], const int cost[], int x[],
+      int pi[])
+{     int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret,
+         *ptr, *arc, *link, *list;
+      /* sanity checks */
+      xassert(nv >= 0);
+      xassert(na >= 0);
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         xassert(1 <= i && i <= nv);
+         xassert(1 <= j && j <= nv);
+         xassert(i != j);
+         xassert(0 <= low[a] && low[a] <= cap[a]);
+      }
+      /* allocate working arrays */
+      ptr = xcalloc(1+nv+1, sizeof(int));
+      arc = xcalloc(1+na+na, sizeof(int));
+      link = xcalloc(1+nv, sizeof(int));
+      list = xcalloc(1+nv, sizeof(int));
+      /* ptr[i] := (degree of node i) */
+      for (i = 1; i <= nv; i++)
+         ptr[i] = 0;
+      for (a = 1; a <= na; a++)
+      {  ptr[tail[a]]++;
+         ptr[head[a]]++;
+      }
+      /* initialize arc pointers */
+      ptr[1]++;
+      for (i = 1; i < nv; i++)
+         ptr[i+1] += ptr[i];
+      ptr[nv+1] = ptr[nv];
+      /* build arc lists */
+      for (a = 1; a <= na; a++)
+      {  arc[--ptr[tail[a]]] = a;
+         arc[--ptr[head[a]]] = a;
+      }
+      xassert(ptr[1] == 1);
+      xassert(ptr[nv+1] == na+na+1);
+      /* now the indices of arcs incident to node i are stored in
+         locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
+      /* initialize arc flows and node potentials */
+      for (a = 1; a <= na; a++)
+         x[a] = 0;
+      for (i = 1; i <= nv; i++)
+         pi[i] = 0;
+loop: /* main loop starts here */
+      /* find out-of-kilter arc */
+      aok = 0;
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         if (overflow(cost[a], pi[i] - pi[j]))
+         {  ret = 2;
+            goto done;
+         }
+         lambda = cost[a] + (pi[i] - pi[j]);
+         if (x[a] < low[a] || lambda < 0 && x[a] < cap[a])
+         {  /* arc a = i->j is out of kilter, and we need to increase
+               the flow through this arc */
+            aok = a, s = j, t = i;
+            break;
+         }
+         if (x[a] > cap[a] || lambda > 0 && x[a] > low[a])
+         {  /* arc a = i->j is out of kilter, and we need to decrease
+               the flow through this arc */
+            aok = a, s = i, t = j;
+            break;
+         }
+      }
+      if (aok == 0)
+      {  /* all arcs are in kilter */
+         /* check for feasibility */
+         for (a = 1; a <= na; a++)
+         {  if (!(low[a] <= x[a] && x[a] <= cap[a]))
+            {  ret = 3;
+               goto done;
+            }
+         }
+         for (i = 1; i <= nv; i++)
+         {  temp = 0;
+            for (k = ptr[i]; k < ptr[i+1]; k++)
+            {  a = arc[k];
+               if (tail[a] == i)
+               {  /* a is outgoing arc */
+                  temp += x[a];
+               }
+               else if (head[a] == i)
+               {  /* a is incoming arc */
+                  temp -= x[a];
+               }
+               else
+                  xassert(a != a);
+            }
+            if (temp != 0)
+            {  ret = 3;
+               goto done;
+            }
+         }
+         /* check for optimality */
+         for (a = 1; a <= na; a++)
+         {  i = tail[a], j = head[a];
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (lambda > 0 && x[a] != low[a] ||
+                lambda < 0 && x[a] != cap[a])
+            {  ret = 3;
+               goto done;
+            }
+         }
+         /* current circulation is optimal */
+         ret = 0;
+         goto done;
+      }
+      /* now we need to find a cycle (t, a, s, ..., t), which allows
+         increasing the flow along it, where a is the out-of-kilter arc
+         just found */
+      /* link[i] = 0 means that node i is not labelled yet;
+         link[i] = a means that arc a immediately precedes node i */
+      /* initially only node s is labelled */
+      for (i = 1; i <= nv; i++)
+         link[i] = 0;
+      link[s] = aok, list[1] = s, pos1 = pos2 = 1;
+      /* breadth first search */
+      while (pos1 <= pos2)
+      {  /* dequeue node i */
+         i = list[pos1++];
+         /* consider all arcs incident to node i */
+         for (k = ptr[i]; k < ptr[i+1]; k++)
+         {  a = arc[k];
+            if (tail[a] == i)
+            {  /* a = i->j is a forward arc from s to t */
+               j = head[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow increasing the flow through
+                  it, skip the arc */
+               if (x[a] >= cap[a]) continue;
+               if (overflow(cost[a], pi[i] - pi[j]))
+               {  ret = 2;
+                  goto done;
+               }
+               lambda = cost[a] + (pi[i] - pi[j]);
+               if (lambda > 0 && x[a] >= low[a]) continue;
+            }
+            else if (head[a] == i)
+            {  /* a = i<-j is a backward arc from s to t */
+               j = tail[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow decreasing the flow through
+                  it, skip the arc */
+               if (x[a] <= low[a]) continue;
+               if (overflow(cost[a], pi[j] - pi[i]))
+               {  ret = 2;
+                  goto done;
+               }
+               lambda = cost[a] + (pi[j] - pi[i]);
+               if (lambda < 0 && x[a] <= cap[a]) continue;
+            }
+            else
+               xassert(a != a);
+            /* label node j and enqueue it */
+            link[j] = a, list[++pos2] = j;
+            /* check for breakthrough */
+            if (j == t) goto brkt;
+         }
+      }
+      /* NONBREAKTHROUGH */
+      /* consider all arcs, whose one endpoint is labelled and other is
+         not, and determine maximal change of node potentials */
+      delta = 0;
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         if (link[i] != 0 && link[j] == 0)
+         {  /* a = i->j, where node i is labelled, node j is not */
+            if (overflow(cost[a], pi[i] - pi[j]))
+            {  ret = 2;
+               goto done;
+            }
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (x[a] <= cap[a] && lambda > 0)
+               if (delta == 0 || delta > + lambda) delta = + lambda;
+         }
+         else if (link[i] == 0 && link[j] != 0)
+         {  /* a = j<-i, where node j is labelled, node i is not */
+            if (overflow(cost[a], pi[i] - pi[j]))
+            {  ret = 2;
+               goto done;
+            }
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (x[a] >= low[a] && lambda < 0)
+               if (delta == 0 || delta > - lambda) delta = - lambda;
+         }
+      }
+      if (delta == 0)
+      {  /* there is no feasible circulation */
+         ret = 1;
+         goto done;
+      }
+      /* increase potentials of all unlabelled nodes */
+      for (i = 1; i <= nv; i++)
+      {  if (link[i] == 0)
+         {  if (overflow(pi[i], delta))
+            {  ret = 2;
+               goto done;
+            }
+            pi[i] += delta;
+         }
+      }
+      goto loop;
+brkt: /* BREAKTHROUGH */
+      /* walk through arcs of the cycle (t, a, s, ..., t) found in the
+         reverse order and determine maximal change of the flow */
+      delta = 0;
+      for (j = t;; j = i)
+      {  /* arc a immediately precedes node j in the cycle */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            lambda = cost[a] + (pi[i] - pi[j]);
+            if (lambda > 0 && x[a] < low[a])
+            {  /* x[a] may be increased until its lower bound */
+               temp = low[a] - x[a];
+            }
+            else if (lambda <= 0 && x[a] < cap[a])
+            {  /* x[a] may be increased until its upper bound */
+               temp = cap[a] - x[a];
+            }
+            else
+               xassert(a != a);
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            lambda = cost[a] + (pi[j] - pi[i]);
+            if (lambda < 0 && x[a] > cap[a])
+            {  /* x[a] may be decreased until its upper bound */
+               temp = x[a] - cap[a];
+            }
+            else if (lambda >= 0 && x[a] > low[a])
+            {  /* x[a] may be decreased until its lower bound */
+               temp = x[a] - low[a];
+            }
+            else
+               xassert(a != a);
+         }
+         else
+            xassert(a != a);
+         if (delta == 0 || delta > temp) delta = temp;
+         /* check for end of the cycle */
+         if (i == t) break;
+      }
+      xassert(delta > 0);
+      /* increase the flow along the cycle */
+      for (j = t;; j = i)
+      {  /* arc a immediately precedes node j in the cycle */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            /* overflow cannot occur */
+            x[a] += delta;
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            /* overflow cannot occur */
+            x[a] -= delta;
+         }
+         else
+            xassert(a != a);
+         /* check for end of the cycle */
+         if (i == t) break;
+      }
+      goto loop;
+done: /* free working arrays */
+      xfree(ptr);
+      xfree(arc);
+      xfree(link);
+      xfree(list);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpnet07.c
===================================================================
--- deps/glpk/src/glpnet07.c	(revision 9)
+++ deps/glpk/src/glpnet07.c	(revision 9)
@@ -0,0 +1,222 @@
+/* glpnet07.c (Ford-Fulkerson algorithm) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  ffalg - Ford-Fulkerson algorithm
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  void ffalg(int nv, int na, const int tail[], const int head[],
+*     int s, int t, const int cap[], int x[], char cut[]);
+*
+*  DESCRIPTION
+*
+*  The routine ffalg implements the Ford-Fulkerson algorithm to find a
+*  maximal flow in the specified flow network.
+*
+*  INPUT PARAMETERS
+*
+*  nv is the number of nodes, nv >= 2.
+*
+*  na is the number of arcs, na >= 0.
+*
+*  tail[a], a = 1,...,na, is the index of tail node of arc a.
+*
+*  head[a], a = 1,...,na, is the index of head node of arc a.
+*
+*  s is the source node index, 1 <= s <= nv.
+*
+*  t is the sink node index, 1 <= t <= nv, t != s.
+*
+*  cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0.
+*
+*  NOTE: Multiple arcs are allowed, but self-loops are not allowed.
+*
+*  OUTPUT PARAMETERS
+*
+*  x[a], a = 1,...,na, is optimal value of the flow through arc a.
+*
+*  cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise.
+*  The set of arcs, whose one endpoint is labelled and other is not,
+*  defines the minimal cut corresponding to the maximal flow found.
+*  If the parameter cut is NULL, the cut information are not stored.
+*
+*  REFERENCES
+*
+*  L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND
+*  Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow,"
+*  pp.30-33. */
+
+void ffalg(int nv, int na, const int tail[], const int head[],
+      int s, int t, const int cap[], int x[], char cut[])
+{     int a, delta, i, j, k, pos1, pos2, temp,
+         *ptr, *arc, *link, *list;
+      /* sanity checks */
+      xassert(nv >= 2);
+      xassert(na >= 0);
+      xassert(1 <= s && s <= nv);
+      xassert(1 <= t && t <= nv);
+      xassert(s != t);
+      for (a = 1; a <= na; a++)
+      {  i = tail[a], j = head[a];
+         xassert(1 <= i && i <= nv);
+         xassert(1 <= j && j <= nv);
+         xassert(i != j);
+         xassert(cap[a] >= 0);
+      }
+      /* allocate working arrays */
+      ptr = xcalloc(1+nv+1, sizeof(int));
+      arc = xcalloc(1+na+na, sizeof(int));
+      link = xcalloc(1+nv, sizeof(int));
+      list = xcalloc(1+nv, sizeof(int));
+      /* ptr[i] := (degree of node i) */
+      for (i = 1; i <= nv; i++)
+         ptr[i] = 0;
+      for (a = 1; a <= na; a++)
+      {  ptr[tail[a]]++;
+         ptr[head[a]]++;
+      }
+      /* initialize arc pointers */
+      ptr[1]++;
+      for (i = 1; i < nv; i++)
+         ptr[i+1] += ptr[i];
+      ptr[nv+1] = ptr[nv];
+      /* build arc lists */
+      for (a = 1; a <= na; a++)
+      {  arc[--ptr[tail[a]]] = a;
+         arc[--ptr[head[a]]] = a;
+      }
+      xassert(ptr[1] == 1);
+      xassert(ptr[nv+1] == na+na+1);
+      /* now the indices of arcs incident to node i are stored in
+         locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */
+      /* initialize arc flows */
+      for (a = 1; a <= na; a++)
+         x[a] = 0;
+loop: /* main loop starts here */
+      /* build augmenting tree rooted at s */
+      /* link[i] = 0 means that node i is not labelled yet;
+         link[i] = a means that arc a immediately precedes node i */
+      /* initially node s is labelled as the root */
+      for (i = 1; i <= nv; i++)
+         link[i] = 0;
+      link[s] = -1, list[1] = s, pos1 = pos2 = 1;
+      /* breadth first search */
+      while (pos1 <= pos2)
+      {  /* dequeue node i */
+         i = list[pos1++];
+         /* consider all arcs incident to node i */
+         for (k = ptr[i]; k < ptr[i+1]; k++)
+         {  a = arc[k];
+            if (tail[a] == i)
+            {  /* a = i->j is a forward arc from s to t */
+               j = head[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow increasing the flow through
+                  it, skip the arc */
+               if (x[a] == cap[a]) continue;
+            }
+            else if (head[a] == i)
+            {  /* a = i<-j is a backward arc from s to t */
+               j = tail[a];
+               /* if node j has been labelled, skip the arc */
+               if (link[j] != 0) continue;
+               /* if the arc does not allow decreasing the flow through
+                  it, skip the arc */
+               if (x[a] == 0) continue;
+            }
+            else
+               xassert(a != a);
+            /* label node j and enqueue it */
+            link[j] = a, list[++pos2] = j;
+            /* check for breakthrough */
+            if (j == t) goto brkt;
+         }
+      }
+      /* NONBREAKTHROUGH */
+      /* no augmenting path exists; current flow is maximal */
+      /* store minimal cut information, if necessary */
+      if (cut != NULL)
+      {  for (i = 1; i <= nv; i++)
+            cut[i] = (char)(link[i] != 0);
+      }
+      goto done;
+brkt: /* BREAKTHROUGH */
+      /* walk through arcs of the augmenting path (s, ..., t) found in
+         the reverse order and determine maximal change of the flow */
+      delta = 0;
+      for (j = t; j != s; j = i)
+      {  /* arc a immediately precedes node j in the path */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            /* x[a] may be increased until its upper bound */
+            temp = cap[a] - x[a];
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            /* x[a] may be decreased until its lower bound */
+            temp = x[a];
+         }
+         else
+            xassert(a != a);
+         if (delta == 0 || delta > temp) delta = temp;
+      }
+      xassert(delta > 0);
+      /* increase the flow along the path */
+      for (j = t; j != s; j = i)
+      {  /* arc a immediately precedes node j in the path */
+         a = link[j];
+         if (head[a] == j)
+         {  /* a = i->j is a forward arc of the cycle */
+            i = tail[a];
+            x[a] += delta;
+         }
+         else if (tail[a] == j)
+         {  /* a = i<-j is a backward arc of the cycle */
+            i = head[a];
+            x[a] -= delta;
+         }
+         else
+            xassert(a != a);
+      }
+      goto loop;
+done: /* free working arrays */
+      xfree(ptr);
+      xfree(arc);
+      xfree(link);
+      xfree(list);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpnet08.c
===================================================================
--- deps/glpk/src/glpnet08.c	(revision 9)
+++ deps/glpk/src/glpnet08.c	(revision 9)
@@ -0,0 +1,241 @@
+/* glpnet08.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Two subroutines sub() and wclique() below are intended to find a
+*  maximum weight clique in a given undirected graph. These subroutines
+*  are slightly modified version of the program WCLIQUE developed by
+*  Patric Ostergard <http://www.tcs.hut.fi/~pat/wclique.html> and based
+*  on ideas from the article "P. R. J. Ostergard, A new algorithm for
+*  the maximum-weight clique problem, submitted for publication", which
+*  in turn is a generalization of the algorithm for unweighted graphs
+*  presented in "P. R. J. Ostergard, A fast algorithm for the maximum
+*  clique problem, submitted for publication".
+*
+*  USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE.
+*
+*  Changes were made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  wclique - find maximum weight clique with Ostergard's algorithm
+*
+*  SYNOPSIS
+*
+*  int wclique(int n, const int w[], const unsigned char a[],
+*     int ind[]);
+*
+*  DESCRIPTION
+*
+*  The routine wclique finds a maximum weight clique in an undirected
+*  graph with Ostergard's algorithm.
+*
+*  INPUT PARAMETERS
+*
+*  n is the number of vertices, n > 0.
+*
+*  w[i], i = 1,...,n, is a weight of vertex i.
+*
+*  a[*] is the strict (without main diagonal) lower triangle of the
+*  graph adjacency matrix in packed format.
+*
+*  OUTPUT PARAMETER
+*
+*  ind[k], k = 1,...,size, is the number of a vertex included in the
+*  clique found, 1 <= ind[k] <= n, where size is the number of vertices
+*  in the clique returned on exit.
+*
+*  RETURNS
+*
+*  The routine returns the clique size, i.e. the number of vertices in
+*  the clique. */
+
+struct csa
+{     /* common storage area */
+      int n;
+      /* number of vertices */
+      const int *wt; /* int wt[0:n-1]; */
+      /* weights */
+      const unsigned char *a;
+      /* adjacency matrix (packed lower triangle without main diag.) */
+      int record;
+      /* weight of best clique */
+      int rec_level;
+      /* number of vertices in best clique */
+      int *rec; /* int rec[0:n-1]; */
+      /* best clique so far */
+      int *clique; /* int clique[0:n-1]; */
+      /* table for pruning */
+      int *set; /* int set[0:n-1]; */
+      /* current clique */
+};
+
+#define n         (csa->n)
+#define wt        (csa->wt)
+#define a         (csa->a)
+#define record    (csa->record)
+#define rec_level (csa->rec_level)
+#define rec       (csa->rec)
+#define clique    (csa->clique)
+#define set       (csa->set)
+
+#if 0
+static int is_edge(struct csa *csa, int i, int j)
+{     /* if there is arc (i,j), the routine returns true; otherwise
+         false; 0 <= i, j < n */
+      int k;
+      xassert(0 <= i && i < n);
+      xassert(0 <= j && j < n);
+      if (i == j) return 0;
+      if (i < j) k = i, i = j, j = k;
+      k = (i * (i - 1)) / 2 + j;
+      return a[k / CHAR_BIT] &
+         (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT));
+}
+#else
+#define is_edge(csa, i, j) ((i) == (j) ? 0 : \
+      (i) > (j) ? is_edge1(i, j) : is_edge1(j, i))
+#define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j))
+#define is_edge2(k) (a[(k) / CHAR_BIT] & \
+      (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT)))
+#endif
+
+static void sub(struct csa *csa, int ct, int table[], int level,
+      int weight, int l_weight)
+{     int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable;
+      newtable = xcalloc(n, sizeof(int));
+      if (ct <= 0)
+      {  /* 0 or 1 elements left; include these */
+         if (ct == 0)
+         {  set[level++] = table[0];
+            weight += l_weight;
+         }
+         if (weight > record)
+         {  record = weight;
+            rec_level = level;
+            for (i = 0; i < level; i++) rec[i] = set[i];
+         }
+         goto done;
+      }
+      for (i = ct; i >= 0; i--)
+      {  if ((level == 0) && (i < ct)) goto done;
+         k = table[i];
+         if ((level > 0) && (clique[k] <= (record - weight)))
+            goto done; /* prune */
+         set[level] = k;
+         curr_weight = weight + wt[k];
+         l_weight -= wt[k];
+         if (l_weight <= (record - curr_weight))
+            goto done; /* prune */
+         p1 = newtable;
+         p2 = table;
+         left_weight = 0;
+         while (p2 < table + i)
+         {  j = *p2++;
+            if (is_edge(csa, j, k))
+            {  *p1++ = j;
+               left_weight += wt[j];
+            }
+         }
+         if (left_weight <= (record - curr_weight)) continue;
+         sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight,
+            left_weight);
+      }
+done: xfree(newtable);
+      return;
+}
+
+int wclique(int _n, const int w[], const unsigned char _a[], int ind[])
+{     struct csa _csa, *csa = &_csa;
+      int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos;
+      glp_long timer;
+      n = _n;
+      xassert(n > 0);
+      wt = &w[1];
+      a = _a;
+      record = 0;
+      rec_level = 0;
+      rec = &ind[1];
+      clique = xcalloc(n, sizeof(int));
+      set = xcalloc(n, sizeof(int));
+      used = xcalloc(n, sizeof(int));
+      nwt = xcalloc(n, sizeof(int));
+      pos = xcalloc(n, sizeof(int));
+      /* start timer */
+      timer = xtime();
+      /* order vertices */
+      for (i = 0; i < n; i++)
+      {  nwt[i] = 0;
+         for (j = 0; j < n; j++)
+            if (is_edge(csa, i, j)) nwt[i] += wt[j];
+      }
+      for (i = 0; i < n; i++)
+         used[i] = 0;
+      for (i = n-1; i >= 0; i--)
+      {  max_wt = -1;
+         max_nwt = -1;
+         for (j = 0; j < n; j++)
+         {  if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt
+               && nwt[j] > max_nwt)))
+            {  max_wt = wt[j];
+               max_nwt = nwt[j];
+               p = j;
+            }
+         }
+         pos[i] = p;
+         used[p] = 1;
+         for (j = 0; j < n; j++)
+            if ((!used[j]) && (j != p) && (is_edge(csa, p, j)))
+               nwt[j] -= wt[p];
+      }
+      /* main routine */
+      wth = 0;
+      for (i = 0; i < n; i++)
+      {  wth += wt[pos[i]];
+         sub(csa, i, pos, 0, 0, wth);
+         clique[pos[i]] = record;
+         if (xdifftime(xtime(), timer) >= 5.0 - 0.001)
+         {  /* print current record and reset timer */
+            xprintf("level = %d (%d); best = %d\n", i+1, n, record);
+            timer = xtime();
+         }
+      }
+      xfree(clique);
+      xfree(set);
+      xfree(used);
+      xfree(nwt);
+      xfree(pos);
+      /* return the solution found */
+      for (i = 1; i <= rec_level; i++) ind[i]++;
+      return rec_level;
+}
+
+#undef n
+#undef wt
+#undef a
+#undef record
+#undef rec_level
+#undef rec
+#undef clique
+#undef set
+
+/* eof */
Index: deps/glpk/src/glpnet09.c
===================================================================
--- deps/glpk/src/glpnet09.c	(revision 9)
+++ deps/glpk/src/glpnet09.c	(revision 9)
@@ -0,0 +1,235 @@
+/* glpnet09.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+#include "glpnet.h"
+
+/***********************************************************************
+*  NAME
+*
+*  kellerman - cover edges by cliques with Kellerman's heuristic
+*
+*  SYNOPSIS
+*
+*  #include "glpnet.h"
+*  int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+*     void *info, glp_graph *H);
+*
+*  DESCRIPTION
+*
+*  The routine kellerman implements Kellerman's heuristic algorithm
+*  to find a minimal set of cliques which cover all edges of specified
+*  graph G = (V, E).
+*
+*  The parameter n specifies the number of vertices |V|, n >= 0.
+*
+*  Formal routine func specifies the set of edges E in the following
+*  way. Running the routine kellerman calls the routine func and passes
+*  to it parameter i, which is the number of some vertex, 1 <= i <= n.
+*  In response the routine func should store numbers of all vertices
+*  adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and
+*  return the value of len, which is the number of adjacent vertices,
+*  0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges
+*  are not allowed.
+*
+*  The parameter info is a transit pointer (magic cookie) passed to the
+*  formal routine func as its first parameter.
+*
+*  The result provided by the routine kellerman is the bipartite graph
+*  H = (V union C, F), which defines the covering found. (The program
+*  object of type glp_graph specified by the parameter H should be
+*  previously created with the routine glp_create_graph. On entry the
+*  routine kellerman erases the content of this object with the routine
+*  glp_erase_graph.) Vertices of first part V correspond to vertices of
+*  the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices
+*  of second part C correspond to cliques and have ordinal numbers
+*  n+1, n+2, ..., n+k, where k is the total number of cliques in the
+*  edge covering found. Every edge f in F in the program object H is
+*  represented as arc f = (i->j), where i in V and j in C, which means
+*  that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus,
+*  if two vertices of the graph G are in the same clique, these vertices
+*  are adjacent in G, and corresponding edge is covered by that clique.)
+*
+*  RETURNS
+*
+*  The routine Kellerman returns k, the total number of cliques in the
+*  edge covering found.
+*
+*  REFERENCE
+*
+*  For more details see: glpk/doc/notes/keller.pdf (in Russian). */
+
+struct set
+{     /* set of vertices */
+      int size;
+      /* size (cardinality) of the set, 0 <= card <= n */
+      int *list; /* int list[1+n]; */
+      /* the set contains vertices list[1,...,size] */
+      int *pos; /* int pos[1+n]; */
+      /* pos[i] > 0 means that vertex i is in the set and
+         list[pos[i]] = i; pos[i] = 0 means that vertex i is not in
+         the set */
+};
+
+int kellerman(int n, int (*func)(void *info, int i, int ind[]),
+      void *info, void /* glp_graph */ *H_)
+{     glp_graph *H = H_;
+      struct set W_, *W = &W_, V_, *V = &V_;
+      glp_arc *a;
+      int i, j, k, m, t, len, card, best;
+      xassert(n >= 0);
+      /* H := (V, 0; 0), where V is the set of vertices of graph G */
+      glp_erase_graph(H, H->v_size, H->a_size);
+      glp_add_vertices(H, n);
+      /* W := 0 */
+      W->size = 0;
+      W->list = xcalloc(1+n, sizeof(int));
+      W->pos = xcalloc(1+n, sizeof(int));
+      memset(&W->pos[1], 0, sizeof(int) * n);
+      /* V := 0 */
+      V->size = 0;
+      V->list = xcalloc(1+n, sizeof(int));
+      V->pos = xcalloc(1+n, sizeof(int));
+      memset(&V->pos[1], 0, sizeof(int) * n);
+      /* main loop */
+      for (i = 1; i <= n; i++)
+      {  /* W must be empty */
+         xassert(W->size == 0);
+         /* W := { j : i > j and (i,j) in E } */
+         len = func(info, i, W->list);
+         xassert(0 <= len && len <= n);
+         for (t = 1; t <= len; t++)
+         {  j = W->list[t];
+            xassert(1 <= j && j <= n);
+            if (j >= i) continue;
+            xassert(W->pos[j] == 0);
+            W->list[++W->size] = j, W->pos[j] = W->size;
+         }
+         /* on i-th iteration we need to cover edges (i,j) for all
+            j in W */
+         /* if W is empty, it is a special case */
+         if (W->size == 0)
+         {  /* set k := k + 1 and create new clique C[k] = { i } */
+            k = glp_add_vertices(H, 1) - n;
+            glp_add_arc(H, i, n + k);
+            continue;
+         }
+         /* try to include vertex i into existing cliques */
+         /* V must be empty */
+         xassert(V->size == 0);
+         /* k is the number of cliques found so far */
+         k = H->nv - n;
+         for (m = 1; m <= k; m++)
+         {  /* do while V != W; since here V is within W, we can use
+               equivalent condition: do while |V| < |W| */
+            if (V->size == W->size) break;
+            /* check if C[m] is within W */
+            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+            {  j = a->tail->i;
+               if (W->pos[j] == 0) break;
+            }
+            if (a != NULL) continue;
+            /* C[m] is within W, expand clique C[m] with vertex i */
+            /* C[m] := C[m] union {i} */
+            glp_add_arc(H, i, n + m);
+            /* V is a set of vertices whose incident edges are already
+               covered by existing cliques */
+            /* V := V union C[m] */
+            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+            {  j = a->tail->i;
+               if (V->pos[j] == 0)
+                  V->list[++V->size] = j, V->pos[j] = V->size;
+            }
+         }
+         /* remove from set W the vertices whose incident edges are
+            already covered by existing cliques */
+         /* W := W \ V, V := 0 */
+         for (t = 1; t <= V->size; t++)
+         {  j = V->list[t], V->pos[j] = 0;
+            if (W->pos[j] != 0)
+            {  /* remove vertex j from W */
+               if (W->pos[j] != W->size)
+               {  int jj = W->list[W->size];
+                  W->list[W->pos[j]] = jj;
+                  W->pos[jj] = W->pos[j];
+               }
+               W->size--, W->pos[j] = 0;
+            }
+         }
+         V->size = 0;
+         /* now set W contains only vertices whose incident edges are
+            still not covered by existing cliques; create new cliques
+            to cover remaining edges until set W becomes empty */
+         while (W->size > 0)
+         {  /* find clique C[m], 1 <= m <= k, which shares maximal
+               number of vertices with W; to break ties choose clique
+               having smallest number m */
+            m = 0, best = -1;
+            k = H->nv - n;
+            for (t = 1; t <= k; t++)
+            {  /* compute cardinality of intersection of W and C[t] */
+               card = 0;
+               for (a = H->v[n + t]->in; a != NULL; a = a->h_next)
+               {  j = a->tail->i;
+                  if (W->pos[j] != 0) card++;
+               }
+               if (best < card)
+                  m = t, best = card;
+            }
+            xassert(m > 0);
+            /* set k := k + 1 and create new clique:
+               C[k] := (W intersect C[m]) union { i }, which covers all
+               edges incident to vertices from (W intersect C[m]) */
+            k = glp_add_vertices(H, 1) - n;
+            for (a = H->v[n + m]->in; a != NULL; a = a->h_next)
+            {  j = a->tail->i;
+               if (W->pos[j] != 0)
+               {  /* vertex j is in both W and C[m]; include it in new
+                     clique C[k] */
+                  glp_add_arc(H, j, n + k);
+                  /* remove vertex j from W, since edge (i,j) will be
+                     covered by new clique C[k] */
+                  if (W->pos[j] != W->size)
+                  {  int jj = W->list[W->size];
+                     W->list[W->pos[j]] = jj;
+                     W->pos[jj] = W->pos[j];
+                  }
+                  W->size--, W->pos[j] = 0;
+               }
+            }
+            /* include vertex i to new clique C[k] to cover edges (i,j)
+               incident to all vertices j just removed from W */
+            glp_add_arc(H, i, n + k);
+         }
+      }
+      /* free working arrays */
+      xfree(W->list);
+      xfree(W->pos);
+      xfree(V->list);
+      xfree(V->pos);
+      /* return the number of cliques in the edge covering found */
+      return H->nv - n;
+}
+
+/* eof */
Index: deps/glpk/src/glpnpp.h
===================================================================
--- deps/glpk/src/glpnpp.h	(revision 9)
+++ deps/glpk/src/glpnpp.h	(revision 9)
@@ -0,0 +1,638 @@
+/* glpnpp.h (LP/MIP preprocessor) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPNPP_H
+#define GLPNPP_H
+
+#include "glpapi.h"
+
+typedef struct NPP NPP;
+typedef struct NPPROW NPPROW;
+typedef struct NPPCOL NPPCOL;
+typedef struct NPPAIJ NPPAIJ;
+typedef struct NPPTSE NPPTSE;
+typedef struct NPPLFE NPPLFE;
+
+struct NPP
+{     /* LP/MIP preprocessor workspace */
+      /*--------------------------------------------------------------*/
+      /* original problem segment */
+      int orig_dir;
+      /* optimization direction flag:
+         GLP_MIN - minimization
+         GLP_MAX - maximization */
+      int orig_m;
+      /* number of rows */
+      int orig_n;
+      /* number of columns */
+      int orig_nnz;
+      /* number of non-zero constraint coefficients */
+      /*--------------------------------------------------------------*/
+      /* transformed problem segment (always minimization) */
+      DMP *pool;
+      /* memory pool to store problem components */
+      char *name;
+      /* problem name (1 to 255 chars); NULL means no name is assigned
+         to the problem */
+      char *obj;
+      /* objective function name (1 to 255 chars); NULL means no name
+         is assigned to the objective function */
+      double c0;
+      /* constant term of the objective function */
+      int nrows;
+      /* number of rows introduced into the problem; this count
+         increases by one every time a new row is added and never
+         decreases; thus, actual number of rows may be less than nrows
+         due to row deletions */
+      int ncols;
+      /* number of columns introduced into the problem; this count
+         increases by one every time a new column is added and never
+         decreases; thus, actual number of column may be less than
+         ncols due to column deletions */
+      NPPROW *r_head;
+      /* pointer to the beginning of the row list */
+      NPPROW *r_tail;
+      /* pointer to the end of the row list */
+      NPPCOL *c_head;
+      /* pointer to the beginning of the column list */
+      NPPCOL *c_tail;
+      /* pointer to the end of the column list */
+      /*--------------------------------------------------------------*/
+      /* transformation history */
+      DMP *stack;
+      /* memory pool to store transformation entries */
+      NPPTSE *top;
+      /* pointer to most recent transformation entry */
+#if 0 /* 16/XII-2009 */
+      int count[1+25];
+      /* transformation statistics */
+#endif
+      /*--------------------------------------------------------------*/
+      /* resultant (preprocessed) problem segment */
+      int m;
+      /* number of rows */
+      int n;
+      /* number of columns */
+      int nnz;
+      /* number of non-zero constraint coefficients */
+      int *row_ref; /* int row_ref[1+m]; */
+      /* row_ref[i], 1 <= i <= m, is the reference number assigned to
+         a row, which is i-th row of the resultant problem */
+      int *col_ref; /* int col_ref[1+n]; */
+      /* col_ref[j], 1 <= j <= n, is the reference number assigned to
+         a column, which is j-th column of the resultant problem */
+      /*--------------------------------------------------------------*/
+      /* recovered solution segment */
+      int sol;
+      /* solution indicator:
+         GLP_SOL - basic solution
+         GLP_IPT - interior-point solution
+         GLP_MIP - mixed integer solution */
+      int scaling;
+      /* scaling option:
+         GLP_OFF - scaling is disabled
+         GLP_ON  - scaling is enabled */
+      int p_stat;
+      /* status of primal basic solution:
+         GLP_UNDEF  - primal solution is undefined
+         GLP_FEAS   - primal solution is feasible
+         GLP_INFEAS - primal solution is infeasible
+         GLP_NOFEAS - no primal feasible solution exists */
+      int d_stat;
+      /* status of dual basic solution:
+         GLP_UNDEF  - dual solution is undefined
+         GLP_FEAS   - dual solution is feasible
+         GLP_INFEAS - dual solution is infeasible
+         GLP_NOFEAS - no dual feasible solution exists */
+      int t_stat;
+      /* status of interior-point solution:
+         GLP_UNDEF  - interior solution is undefined
+         GLP_OPT    - interior solution is optimal */
+      int i_stat;
+      /* status of mixed integer solution:
+         GLP_UNDEF  - integer solution is undefined
+         GLP_OPT    - integer solution is optimal
+         GLP_FEAS   - integer solution is feasible
+         GLP_NOFEAS - no integer solution exists */
+      char *r_stat; /* char r_stat[1+nrows]; */
+      /* r_stat[i], 1 <= i <= nrows, is status of i-th row:
+         GLP_BS - inactive constraint
+         GLP_NL - active constraint on lower bound
+         GLP_NU - active constraint on upper bound
+         GLP_NF - active free row
+         GLP_NS - active equality constraint */
+      char *c_stat; /* char c_stat[1+nrows]; */
+      /* c_stat[j], 1 <= j <= nrows, is status of j-th column:
+         GLP_BS - basic variable
+         GLP_NL - non-basic variable on lower bound
+         GLP_NU - non-basic variable on upper bound
+         GLP_NF - non-basic free variable
+         GLP_NS - non-basic fixed variable */
+      double *r_pi; /* double r_pi[1+nrows]; */
+      /* r_pi[i], 1 <= i <= nrows, is Lagrange multiplier (dual value)
+         for i-th row (constraint) */
+      double *c_value; /* double c_value[1+ncols]; */
+      /* c_value[j], 1 <= j <= ncols, is primal value of j-th column
+         (structural variable) */
+};
+
+struct NPPROW
+{     /* row (constraint) */
+      int i;
+      /* reference number assigned to the row, 1 <= i <= nrows */
+      char *name;
+      /* row name (1 to 255 chars); NULL means no name is assigned to
+         the row */
+      double lb;
+      /* lower bound; -DBL_MAX means the row has no lower bound */
+      double ub;
+      /* upper bound; +DBL_MAX means the row has no upper bound */
+      NPPAIJ *ptr;
+      /* pointer to the linked list of constraint coefficients */
+      int temp;
+      /* working field used by preprocessor routines */
+      NPPROW *prev;
+      /* pointer to previous row in the row list */
+      NPPROW *next;
+      /* pointer to next row in the row list */
+};
+
+struct NPPCOL
+{     /* column (variable) */
+      int j;
+      /* reference number assigned to the column, 1 <= j <= ncols */
+      char *name;
+      /* column name (1 to 255 chars); NULL means no name is assigned
+         to the column */
+      char is_int;
+      /* 0 means continuous variable; 1 means integer variable */
+      double lb;
+      /* lower bound; -DBL_MAX means the column has no lower bound */
+      double ub;
+      /* upper bound; +DBL_MAX means the column has no upper bound */
+      double coef;
+      /* objective coefficient */
+      NPPAIJ *ptr;
+      /* pointer to the linked list of constraint coefficients */
+      int temp;
+      /* working field used by preprocessor routines */
+#if 1 /* 28/XII-2009 */
+      union
+      {  double ll;
+         /* implied column lower bound */
+         int pos;
+         /* vertex ordinal number corresponding to this binary column
+            in the conflict graph (0, if the vertex does not exist) */
+      }  ll;
+      union
+      {  double uu;
+         /* implied column upper bound */
+         int neg;
+         /* vertex ordinal number corresponding to complement of this
+            binary column in the conflict graph (0, if the vertex does
+            not exist) */
+      }  uu;
+#endif
+      NPPCOL *prev;
+      /* pointer to previous column in the column list */
+      NPPCOL *next;
+      /* pointer to next column in the column list */
+};
+
+struct NPPAIJ
+{     /* constraint coefficient */
+      NPPROW *row;
+      /* pointer to corresponding row */
+      NPPCOL *col;
+      /* pointer to corresponding column */
+      double val;
+      /* (non-zero) coefficient value */
+      NPPAIJ *r_prev;
+      /* pointer to previous coefficient in the same row */
+      NPPAIJ *r_next;
+      /* pointer to next coefficient in the same row */
+      NPPAIJ *c_prev;
+      /* pointer to previous coefficient in the same column */
+      NPPAIJ *c_next;
+      /* pointer to next coefficient in the same column */
+};
+
+struct NPPTSE
+{     /* transformation stack entry */
+      int (*func)(NPP *npp, void *info);
+      /* pointer to routine performing back transformation */
+      void *info;
+      /* pointer to specific info (depends on the transformation) */
+      NPPTSE *link;
+      /* pointer to another entry created *before* this entry */
+};
+
+struct NPPLFE
+{     /* linear form element */
+      int ref;
+      /* row/column reference number */
+      double val;
+      /* (non-zero) coefficient value */
+      NPPLFE *next;
+      /* pointer to another element */
+};
+
+#define npp_create_wksp _glp_npp_create_wksp
+NPP *npp_create_wksp(void);
+/* create LP/MIP preprocessor workspace */
+
+#define npp_insert_row _glp_npp_insert_row
+void npp_insert_row(NPP *npp, NPPROW *row, int where);
+/* insert row to the row list */
+
+#define npp_remove_row _glp_npp_remove_row
+void npp_remove_row(NPP *npp, NPPROW *row);
+/* remove row from the row list */
+
+#define npp_activate_row _glp_npp_activate_row
+void npp_activate_row(NPP *npp, NPPROW *row);
+/* make row active */
+
+#define npp_deactivate_row _glp_npp_deactivate_row
+void npp_deactivate_row(NPP *npp, NPPROW *row);
+/* make row inactive */
+
+#define npp_insert_col _glp_npp_insert_col
+void npp_insert_col(NPP *npp, NPPCOL *col, int where);
+/* insert column to the column list */
+
+#define npp_remove_col _glp_npp_remove_col
+void npp_remove_col(NPP *npp, NPPCOL *col);
+/* remove column from the column list */
+
+#define npp_activate_col _glp_npp_activate_col
+void npp_activate_col(NPP *npp, NPPCOL *col);
+/* make column active */
+
+#define npp_deactivate_col _glp_npp_deactivate_col
+void npp_deactivate_col(NPP *npp, NPPCOL *col);
+/* make column inactive */
+
+#define npp_add_row _glp_npp_add_row
+NPPROW *npp_add_row(NPP *npp);
+/* add new row to the current problem */
+
+#define npp_add_col _glp_npp_add_col
+NPPCOL *npp_add_col(NPP *npp);
+/* add new column to the current problem */
+
+#define npp_add_aij _glp_npp_add_aij
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val);
+/* add new element to the constraint matrix */
+
+#define npp_row_nnz _glp_npp_row_nnz
+int npp_row_nnz(NPP *npp, NPPROW *row);
+/* count number of non-zero coefficients in row */
+
+#define npp_col_nnz _glp_npp_col_nnz
+int npp_col_nnz(NPP *npp, NPPCOL *col);
+/* count number of non-zero coefficients in column */
+
+#define npp_push_tse _glp_npp_push_tse
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+      int size);
+/* push new entry to the transformation stack */
+
+#define npp_erase_row _glp_npp_erase_row
+void npp_erase_row(NPP *npp, NPPROW *row);
+/* erase row content to make it empty */
+
+#define npp_del_row _glp_npp_del_row
+void npp_del_row(NPP *npp, NPPROW *row);
+/* remove row from the current problem */
+
+#define npp_del_col _glp_npp_del_col
+void npp_del_col(NPP *npp, NPPCOL *col);
+/* remove column from the current problem */
+
+#define npp_del_aij _glp_npp_del_aij
+void npp_del_aij(NPP *npp, NPPAIJ *aij);
+/* remove element from the constraint matrix */
+
+#define npp_load_prob _glp_npp_load_prob
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+      int scaling);
+/* load original problem into the preprocessor workspace */
+
+#define npp_build_prob _glp_npp_build_prob
+void npp_build_prob(NPP *npp, glp_prob *prob);
+/* build resultant (preprocessed) problem */
+
+#define npp_postprocess _glp_npp_postprocess
+void npp_postprocess(NPP *npp, glp_prob *prob);
+/* postprocess solution from the resultant problem */
+
+#define npp_unload_sol _glp_npp_unload_sol
+void npp_unload_sol(NPP *npp, glp_prob *orig);
+/* store solution to the original problem */
+
+#define npp_delete_wksp _glp_npp_delete_wksp
+void npp_delete_wksp(NPP *npp);
+/* delete LP/MIP preprocessor workspace */
+
+#define npp_error()
+
+#define npp_free_row _glp_npp_free_row
+void npp_free_row(NPP *npp, NPPROW *p);
+/* process free (unbounded) row */
+
+#define npp_geq_row _glp_npp_geq_row
+void npp_geq_row(NPP *npp, NPPROW *p);
+/* process row of 'not less than' type */
+
+#define npp_leq_row _glp_npp_leq_row
+void npp_leq_row(NPP *npp, NPPROW *p);
+/* process row of 'not greater than' type */
+
+#define npp_free_col _glp_npp_free_col
+void npp_free_col(NPP *npp, NPPCOL *q);
+/* process free (unbounded) column */
+
+#define npp_lbnd_col _glp_npp_lbnd_col
+void npp_lbnd_col(NPP *npp, NPPCOL *q);
+/* process column with (non-zero) lower bound */
+
+#define npp_ubnd_col _glp_npp_ubnd_col
+void npp_ubnd_col(NPP *npp, NPPCOL *q);
+/* process column with upper bound */
+
+#define npp_dbnd_col _glp_npp_dbnd_col
+void npp_dbnd_col(NPP *npp, NPPCOL *q);
+/* process non-negative column with upper bound */
+
+#define npp_fixed_col _glp_npp_fixed_col
+void npp_fixed_col(NPP *npp, NPPCOL *q);
+/* process fixed column */
+
+#define npp_make_equality _glp_npp_make_equality
+int npp_make_equality(NPP *npp, NPPROW *p);
+/* process row with almost identical bounds */
+
+#define npp_make_fixed _glp_npp_make_fixed
+int npp_make_fixed(NPP *npp, NPPCOL *q);
+/* process column with almost identical bounds */
+
+#define npp_empty_row _glp_npp_empty_row
+int npp_empty_row(NPP *npp, NPPROW *p);
+/* process empty row */
+
+#define npp_empty_col _glp_npp_empty_col
+int npp_empty_col(NPP *npp, NPPCOL *q);
+/* process empty column */
+
+#define npp_implied_value _glp_npp_implied_value
+int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+/* process implied column value */
+
+#define npp_eq_singlet _glp_npp_eq_singlet
+int npp_eq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (equality constraint) */
+
+#define npp_implied_lower _glp_npp_implied_lower
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+/* process implied column lower bound */
+
+#define npp_implied_upper _glp_npp_implied_upper
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+/* process implied upper bound of column */
+
+#define npp_ineq_singlet _glp_npp_ineq_singlet
+int npp_ineq_singlet(NPP *npp, NPPROW *p);
+/* process row singleton (inequality constraint) */
+
+#define npp_implied_slack _glp_npp_implied_slack
+void npp_implied_slack(NPP *npp, NPPCOL *q);
+/* process column singleton (implied slack variable) */
+
+#define npp_implied_free _glp_npp_implied_free
+int npp_implied_free(NPP *npp, NPPCOL *q);
+/* process column singleton (implied free variable) */
+
+#define npp_eq_doublet _glp_npp_eq_doublet
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+/* process row doubleton (equality constraint) */
+
+#define npp_forcing_row _glp_npp_forcing_row
+int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+/* process forcing row */
+
+#define npp_analyze_row _glp_npp_analyze_row
+int npp_analyze_row(NPP *npp, NPPROW *p);
+/* perform general row analysis */
+
+#define npp_inactive_bound _glp_npp_inactive_bound
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+/* remove row lower/upper inactive bound */
+
+#define npp_implied_bounds _glp_npp_implied_bounds
+void npp_implied_bounds(NPP *npp, NPPROW *p);
+/* determine implied column bounds */
+
+#define npp_binarize_prob _glp_npp_binarize_prob
+int npp_binarize_prob(NPP *npp);
+/* binarize MIP problem */
+
+#define npp_is_packing _glp_npp_is_packing
+int npp_is_packing(NPP *npp, NPPROW *row);
+/* test if constraint is packing inequality */
+
+#define npp_hidden_packing _glp_npp_hidden_packing
+int npp_hidden_packing(NPP *npp, NPPROW *row);
+/* identify hidden packing inequality */
+
+#define npp_implied_packing _glp_npp_implied_packing
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+      NPPCOL *var[], char set[]);
+/* identify implied packing inequality */
+
+#define npp_is_covering _glp_npp_is_covering
+int npp_is_covering(NPP *npp, NPPROW *row);
+/* test if constraint is covering inequality */
+
+#define npp_hidden_covering _glp_npp_hidden_covering
+int npp_hidden_covering(NPP *npp, NPPROW *row);
+/* identify hidden covering inequality */
+
+#define npp_is_partitioning _glp_npp_is_partitioning
+int npp_is_partitioning(NPP *npp, NPPROW *row);
+/* test if constraint is partitioning equality */
+
+#define npp_reduce_ineq_coef _glp_npp_reduce_ineq_coef
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+/* reduce inequality constraint coefficients */
+
+#define npp_clean_prob _glp_npp_clean_prob
+void npp_clean_prob(NPP *npp);
+/* perform initial LP/MIP processing */
+
+#define npp_process_row _glp_npp_process_row
+int npp_process_row(NPP *npp, NPPROW *row, int hard);
+/* perform basic row processing */
+
+#define npp_improve_bounds _glp_npp_improve_bounds
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+/* improve current column bounds */
+
+#define npp_process_col _glp_npp_process_col
+int npp_process_col(NPP *npp, NPPCOL *col);
+/* perform basic column processing */
+
+#define npp_process_prob _glp_npp_process_prob
+int npp_process_prob(NPP *npp, int hard);
+/* perform basic LP/MIP processing */
+
+#define npp_simplex _glp_npp_simplex
+int npp_simplex(NPP *npp, const glp_smcp *parm);
+/* process LP prior to applying primal/dual simplex method */
+
+#define npp_integer _glp_npp_integer
+int npp_integer(NPP *npp, const glp_iocp *parm);
+/* process MIP prior to applying branch-and-bound method */
+
+/**********************************************************************/
+
+#define npp_sat_free_row _glp_npp_sat_free_row
+void npp_sat_free_row(NPP *npp, NPPROW *p);
+/* process free (unbounded) row */
+
+#define npp_sat_fixed_col _glp_npp_sat_fixed_col
+int npp_sat_fixed_col(NPP *npp, NPPCOL *q);
+/* process fixed column */
+
+#define npp_sat_is_bin_comb _glp_npp_sat_is_bin_comb
+int npp_sat_is_bin_comb(NPP *npp, NPPROW *row);
+/* test if row is binary combination */
+
+#define npp_sat_num_pos_coef _glp_npp_sat_num_pos_coef
+int npp_sat_num_pos_coef(NPP *npp, NPPROW *row);
+/* determine number of positive coefficients */
+
+#define npp_sat_num_neg_coef _glp_npp_sat_num_neg_coef
+int npp_sat_num_neg_coef(NPP *npp, NPPROW *row);
+/* determine number of negative coefficients */
+
+#define npp_sat_is_cover_ineq _glp_npp_sat_is_cover_ineq
+int npp_sat_is_cover_ineq(NPP *npp, NPPROW *row);
+/* test if row is covering inequality */
+
+#define npp_sat_is_pack_ineq _glp_npp_sat_is_pack_ineq
+int npp_sat_is_pack_ineq(NPP *npp, NPPROW *row);
+/* test if row is packing inequality */
+
+#define npp_sat_is_partn_eq _glp_npp_sat_is_partn_eq
+int npp_sat_is_partn_eq(NPP *npp, NPPROW *row);
+/* test if row is partitioning equality */
+
+#define npp_sat_reverse_row _glp_npp_sat_reverse_row
+int npp_sat_reverse_row(NPP *npp, NPPROW *row);
+/* multiply both sides of row by -1 */
+
+#define npp_sat_split_pack _glp_npp_sat_split_pack
+NPPROW *npp_sat_split_pack(NPP *npp, NPPROW *row, int nnn);
+/* split packing inequality */
+
+#define npp_sat_encode_pack _glp_npp_sat_encode_pack
+void npp_sat_encode_pack(NPP *npp, NPPROW *row);
+/* encode packing inequality */
+
+typedef struct NPPLIT NPPLIT;
+typedef struct NPPLSE NPPLSE;
+typedef struct NPPSED NPPSED;
+
+struct NPPLIT
+{     /* literal (binary variable or its negation) */
+      NPPCOL *col;
+      /* pointer to binary variable; NULL means constant false */
+      int neg;
+      /* negation flag:
+         0 - literal is variable (or constant false)
+         1 - literal is negation of variable (or constant true) */
+};
+
+struct NPPLSE
+{     /* literal set element */
+      NPPLIT lit;
+      /* literal */
+      NPPLSE *next;
+      /* pointer to another element */
+};
+
+struct NPPSED
+{     /* summation encoding descriptor */
+      /* this struct describes the equality
+            x + y + z = s + 2 * c,
+         which was encoded as CNF and included into the transformed
+         problem; here x and y are literals, z is either a literal or
+         constant zero, s and c are binary variables modeling, resp.,
+         the low and high (carry) sum bits */
+      NPPLIT x, y, z;
+      /* literals; if z.col = NULL, z is constant zero */
+      NPPCOL *s, *c;
+      /* binary variables modeling the sum bits */
+};
+
+#define npp_sat_encode_sum2 _glp_npp_sat_encode_sum2
+void npp_sat_encode_sum2(NPP *npp, NPPLSE *set, NPPSED *sed);
+/* encode 2-bit summation */
+
+#define npp_sat_encode_sum3 _glp_npp_sat_encode_sum3
+void npp_sat_encode_sum3(NPP *npp, NPPLSE *set, NPPSED *sed);
+/* encode 3-bit summation */
+
+#define npp_sat_encode_sum_ax _glp_npp_sat_encode_sum_ax
+int npp_sat_encode_sum_ax(NPP *npp, NPPROW *row, NPPLIT y[]);
+/* encode linear combination of 0-1 variables */
+
+#define npp_sat_normalize_clause _glp_npp_sat_normalize_clause
+int npp_sat_normalize_clause(NPP *npp, int size, NPPLIT lit[]);
+/* normalize clause */
+
+#define npp_sat_encode_clause _glp_npp_sat_encode_clause
+NPPROW *npp_sat_encode_clause(NPP *npp, int size, NPPLIT lit[]);
+/* translate clause to cover inequality */
+
+#define npp_sat_encode_geq _glp_npp_sat_encode_geq
+int npp_sat_encode_geq(NPP *npp, int n, NPPLIT y[], int rhs);
+/* encode "not less than" constraint */
+
+#define npp_sat_encode_leq _glp_npp_sat_encode_leq
+int npp_sat_encode_leq(NPP *npp, int n, NPPLIT y[], int rhs);
+/* encode "not greater than" constraint */
+
+#define npp_sat_encode_row _glp_npp_sat_encode_row
+int npp_sat_encode_row(NPP *npp, NPPROW *row);
+/* encode constraint (row) of general type */
+
+#define npp_sat_encode_prob _glp_npp_sat_encode_prob
+int npp_sat_encode_prob(NPP *npp);
+/* encode 0-1 feasibility problem */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpnpp01.c
===================================================================
--- deps/glpk/src/glpnpp01.c	(revision 9)
+++ deps/glpk/src/glpnpp01.c	(revision 9)
@@ -0,0 +1,927 @@
+/* glpnpp01.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+NPP *npp_create_wksp(void)
+{     /* create LP/MIP preprocessor workspace */
+      NPP *npp;
+      npp = xmalloc(sizeof(NPP));
+      npp->orig_dir = 0;
+      npp->orig_m = npp->orig_n = npp->orig_nnz = 0;
+      npp->pool = dmp_create_pool();
+      npp->name = npp->obj = NULL;
+      npp->c0 = 0.0;
+      npp->nrows = npp->ncols = 0;
+      npp->r_head = npp->r_tail = NULL;
+      npp->c_head = npp->c_tail = NULL;
+      npp->stack = dmp_create_pool();
+      npp->top = NULL;
+#if 0 /* 16/XII-2009 */
+      memset(&npp->count, 0, sizeof(npp->count));
+#endif
+      npp->m = npp->n = npp->nnz = 0;
+      npp->row_ref = npp->col_ref = NULL;
+      npp->sol = npp->scaling = 0;
+      npp->p_stat = npp->d_stat = npp->t_stat = npp->i_stat = 0;
+      npp->r_stat = NULL;
+      /*npp->r_prim =*/ npp->r_pi = NULL;
+      npp->c_stat = NULL;
+      npp->c_value = /*npp->c_dual =*/ NULL;
+      return npp;
+}
+
+void npp_insert_row(NPP *npp, NPPROW *row, int where)
+{     /* insert row to the row list */
+      if (where == 0)
+      {  /* insert row to the beginning of the row list */
+         row->prev = NULL;
+         row->next = npp->r_head;
+         if (row->next == NULL)
+            npp->r_tail = row;
+         else
+            row->next->prev = row;
+         npp->r_head = row;
+      }
+      else
+      {  /* insert row to the end of the row list */
+         row->prev = npp->r_tail;
+         row->next = NULL;
+         if (row->prev == NULL)
+            npp->r_head = row;
+         else
+            row->prev->next = row;
+         npp->r_tail = row;
+      }
+      return;
+}
+
+void npp_remove_row(NPP *npp, NPPROW *row)
+{     /* remove row from the row list */
+      if (row->prev == NULL)
+         npp->r_head = row->next;
+      else
+         row->prev->next = row->next;
+      if (row->next == NULL)
+         npp->r_tail = row->prev;
+      else
+         row->next->prev = row->prev;
+      return;
+}
+
+void npp_activate_row(NPP *npp, NPPROW *row)
+{     /* make row active */
+      if (!row->temp)
+      {  row->temp = 1;
+         /* move the row to the beginning of the row list */
+         npp_remove_row(npp, row);
+         npp_insert_row(npp, row, 0);
+      }
+      return;
+}
+
+void npp_deactivate_row(NPP *npp, NPPROW *row)
+{     /* make row inactive */
+      if (row->temp)
+      {  row->temp = 0;
+         /* move the row to the end of the row list */
+         npp_remove_row(npp, row);
+         npp_insert_row(npp, row, 1);
+      }
+      return;
+}
+
+void npp_insert_col(NPP *npp, NPPCOL *col, int where)
+{     /* insert column to the column list */
+      if (where == 0)
+      {  /* insert column to the beginning of the column list */
+         col->prev = NULL;
+         col->next = npp->c_head;
+         if (col->next == NULL)
+            npp->c_tail = col;
+         else
+            col->next->prev = col;
+         npp->c_head = col;
+      }
+      else
+      {  /* insert column to the end of the column list */
+         col->prev = npp->c_tail;
+         col->next = NULL;
+         if (col->prev == NULL)
+            npp->c_head = col;
+         else
+            col->prev->next = col;
+         npp->c_tail = col;
+      }
+      return;
+}
+
+void npp_remove_col(NPP *npp, NPPCOL *col)
+{     /* remove column from the column list */
+      if (col->prev == NULL)
+         npp->c_head = col->next;
+      else
+         col->prev->next = col->next;
+      if (col->next == NULL)
+         npp->c_tail = col->prev;
+      else
+         col->next->prev = col->prev;
+      return;
+}
+
+void npp_activate_col(NPP *npp, NPPCOL *col)
+{     /* make column active */
+      if (!col->temp)
+      {  col->temp = 1;
+         /* move the column to the beginning of the column list */
+         npp_remove_col(npp, col);
+         npp_insert_col(npp, col, 0);
+      }
+      return;
+}
+
+void npp_deactivate_col(NPP *npp, NPPCOL *col)
+{     /* make column inactive */
+      if (col->temp)
+      {  col->temp = 0;
+         /* move the column to the end of the column list */
+         npp_remove_col(npp, col);
+         npp_insert_col(npp, col, 1);
+      }
+      return;
+}
+
+NPPROW *npp_add_row(NPP *npp)
+{     /* add new row to the current problem */
+      NPPROW *row;
+      row = dmp_get_atom(npp->pool, sizeof(NPPROW));
+      row->i = ++(npp->nrows);
+      row->name = NULL;
+      row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+      row->ptr = NULL;
+      row->temp = 0;
+      npp_insert_row(npp, row, 1);
+      return row;
+}
+
+NPPCOL *npp_add_col(NPP *npp)
+{     /* add new column to the current problem */
+      NPPCOL *col;
+      col = dmp_get_atom(npp->pool, sizeof(NPPCOL));
+      col->j = ++(npp->ncols);
+      col->name = NULL;
+#if 0
+      col->kind = GLP_CV;
+#else
+      col->is_int = 0;
+#endif
+      col->lb = col->ub = col->coef = 0.0;
+      col->ptr = NULL;
+      col->temp = 0;
+      npp_insert_col(npp, col, 1);
+      return col;
+}
+
+NPPAIJ *npp_add_aij(NPP *npp, NPPROW *row, NPPCOL *col, double val)
+{     /* add new element to the constraint matrix */
+      NPPAIJ *aij;
+      aij = dmp_get_atom(npp->pool, sizeof(NPPAIJ));
+      aij->row = row;
+      aij->col = col;
+      aij->val = val;
+      aij->r_prev = NULL;
+      aij->r_next = row->ptr;
+      aij->c_prev = NULL;
+      aij->c_next = col->ptr;
+      if (aij->r_next != NULL)
+         aij->r_next->r_prev = aij;
+      if (aij->c_next != NULL)
+         aij->c_next->c_prev = aij;
+      row->ptr = col->ptr = aij;
+      return aij;
+}
+
+int npp_row_nnz(NPP *npp, NPPROW *row)
+{     /* count number of non-zero coefficients in row */
+      NPPAIJ *aij;
+      int nnz;
+      xassert(npp == npp);
+      nnz = 0;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         nnz++;
+      return nnz;
+}
+
+int npp_col_nnz(NPP *npp, NPPCOL *col)
+{     /* count number of non-zero coefficients in column */
+      NPPAIJ *aij;
+      int nnz;
+      xassert(npp == npp);
+      nnz = 0;
+      for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+         nnz++;
+      return nnz;
+}
+
+void *npp_push_tse(NPP *npp, int (*func)(NPP *npp, void *info),
+      int size)
+{     /* push new entry to the transformation stack */
+      NPPTSE *tse;
+      tse = dmp_get_atom(npp->stack, sizeof(NPPTSE));
+      tse->func = func;
+      tse->info = dmp_get_atom(npp->stack, size);
+      tse->link = npp->top;
+      npp->top = tse;
+      return tse->info;
+}
+
+#if 1 /* 23/XII-2009 */
+void npp_erase_row(NPP *npp, NPPROW *row)
+{     /* erase row content to make it empty */
+      NPPAIJ *aij;
+      while (row->ptr != NULL)
+      {  aij = row->ptr;
+         row->ptr = aij->r_next;
+         if (aij->c_prev == NULL)
+            aij->col->ptr = aij->c_next;
+         else
+            aij->c_prev->c_next = aij->c_next;
+         if (aij->c_next == NULL)
+            ;
+         else
+            aij->c_next->c_prev = aij->c_prev;
+         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      }
+      return;
+}
+#endif
+
+void npp_del_row(NPP *npp, NPPROW *row)
+{     /* remove row from the current problem */
+#if 0 /* 23/XII-2009 */
+      NPPAIJ *aij;
+#endif
+      if (row->name != NULL)
+         dmp_free_atom(npp->pool, row->name, strlen(row->name)+1);
+#if 0 /* 23/XII-2009 */
+      while (row->ptr != NULL)
+      {  aij = row->ptr;
+         row->ptr = aij->r_next;
+         if (aij->c_prev == NULL)
+            aij->col->ptr = aij->c_next;
+         else
+            aij->c_prev->c_next = aij->c_next;
+         if (aij->c_next == NULL)
+            ;
+         else
+            aij->c_next->c_prev = aij->c_prev;
+         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      }
+#else
+      npp_erase_row(npp, row);
+#endif
+      npp_remove_row(npp, row);
+      dmp_free_atom(npp->pool, row, sizeof(NPPROW));
+      return;
+}
+
+void npp_del_col(NPP *npp, NPPCOL *col)
+{     /* remove column from the current problem */
+      NPPAIJ *aij;
+      if (col->name != NULL)
+         dmp_free_atom(npp->pool, col->name, strlen(col->name)+1);
+      while (col->ptr != NULL)
+      {  aij = col->ptr;
+         col->ptr = aij->c_next;
+         if (aij->r_prev == NULL)
+            aij->row->ptr = aij->r_next;
+         else
+            aij->r_prev->r_next = aij->r_next;
+         if (aij->r_next == NULL)
+            ;
+         else
+            aij->r_next->r_prev = aij->r_prev;
+         dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      }
+      npp_remove_col(npp, col);
+      dmp_free_atom(npp->pool, col, sizeof(NPPCOL));
+      return;
+}
+
+void npp_del_aij(NPP *npp, NPPAIJ *aij)
+{     /* remove element from the constraint matrix */
+      if (aij->r_prev == NULL)
+         aij->row->ptr = aij->r_next;
+      else
+         aij->r_prev->r_next = aij->r_next;
+      if (aij->r_next == NULL)
+         ;
+      else
+         aij->r_next->r_prev = aij->r_prev;
+      if (aij->c_prev == NULL)
+         aij->col->ptr = aij->c_next;
+      else
+         aij->c_prev->c_next = aij->c_next;
+      if (aij->c_next == NULL)
+         ;
+      else
+         aij->c_next->c_prev = aij->c_prev;
+      dmp_free_atom(npp->pool, aij, sizeof(NPPAIJ));
+      return;
+}
+
+void npp_load_prob(NPP *npp, glp_prob *orig, int names, int sol,
+      int scaling)
+{     /* load original problem into the preprocessor workspace */
+      int m = orig->m;
+      int n = orig->n;
+      NPPROW **link;
+      int i, j;
+      double dir;
+      xassert(names == GLP_OFF || names == GLP_ON);
+      xassert(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP);
+      xassert(scaling == GLP_OFF || scaling == GLP_ON);
+      if (sol == GLP_MIP) xassert(!scaling);
+      npp->orig_dir = orig->dir;
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      npp->orig_m = m;
+      npp->orig_n = n;
+      npp->orig_nnz = orig->nnz;
+      if (names && orig->name != NULL)
+      {  npp->name = dmp_get_atom(npp->pool, strlen(orig->name)+1);
+         strcpy(npp->name, orig->name);
+      }
+      if (names && orig->obj != NULL)
+      {  npp->obj = dmp_get_atom(npp->pool, strlen(orig->obj)+1);
+         strcpy(npp->obj, orig->obj);
+      }
+      npp->c0 = dir * orig->c0;
+      /* load rows */
+      link = xcalloc(1+m, sizeof(NPPROW *));
+      for (i = 1; i <= m; i++)
+      {  GLPROW *rrr = orig->row[i];
+         NPPROW *row;
+         link[i] = row = npp_add_row(npp);
+         xassert(row->i == i);
+         if (names && rrr->name != NULL)
+         {  row->name = dmp_get_atom(npp->pool, strlen(rrr->name)+1);
+            strcpy(row->name, rrr->name);
+         }
+         if (!scaling)
+         {  if (rrr->type == GLP_FR)
+               row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_LO)
+               row->lb = rrr->lb, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_UP)
+               row->lb = -DBL_MAX, row->ub = rrr->ub;
+            else if (rrr->type == GLP_DB)
+               row->lb = rrr->lb, row->ub = rrr->ub;
+            else if (rrr->type == GLP_FX)
+               row->lb = row->ub = rrr->lb;
+            else
+               xassert(rrr != rrr);
+         }
+         else
+         {  double rii = rrr->rii;
+            if (rrr->type == GLP_FR)
+               row->lb = -DBL_MAX, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_LO)
+               row->lb = rrr->lb * rii, row->ub = +DBL_MAX;
+            else if (rrr->type == GLP_UP)
+               row->lb = -DBL_MAX, row->ub = rrr->ub * rii;
+            else if (rrr->type == GLP_DB)
+               row->lb = rrr->lb * rii, row->ub = rrr->ub * rii;
+            else if (rrr->type == GLP_FX)
+               row->lb = row->ub = rrr->lb * rii;
+            else
+               xassert(rrr != rrr);
+         }
+      }
+      /* load columns and constraint coefficients */
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *ccc = orig->col[j];
+         GLPAIJ *aaa;
+         NPPCOL *col;
+         col = npp_add_col(npp);
+         xassert(col->j == j);
+         if (names && ccc->name != NULL)
+         {  col->name = dmp_get_atom(npp->pool, strlen(ccc->name)+1);
+            strcpy(col->name, ccc->name);
+         }
+         if (sol == GLP_MIP)
+#if 0
+            col->kind = ccc->kind;
+#else
+            col->is_int = (char)(ccc->kind == GLP_IV);
+#endif
+         if (!scaling)
+         {  if (ccc->type == GLP_FR)
+               col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_LO)
+               col->lb = ccc->lb, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_UP)
+               col->lb = -DBL_MAX, col->ub = ccc->ub;
+            else if (ccc->type == GLP_DB)
+               col->lb = ccc->lb, col->ub = ccc->ub;
+            else if (ccc->type == GLP_FX)
+               col->lb = col->ub = ccc->lb;
+            else
+               xassert(ccc != ccc);
+            col->coef = dir * ccc->coef;
+            for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+               npp_add_aij(npp, link[aaa->row->i], col, aaa->val);
+         }
+         else
+         {  double sjj = ccc->sjj;
+            if (ccc->type == GLP_FR)
+               col->lb = -DBL_MAX, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_LO)
+               col->lb = ccc->lb / sjj, col->ub = +DBL_MAX;
+            else if (ccc->type == GLP_UP)
+               col->lb = -DBL_MAX, col->ub = ccc->ub / sjj;
+            else if (ccc->type == GLP_DB)
+               col->lb = ccc->lb / sjj, col->ub = ccc->ub / sjj;
+            else if (ccc->type == GLP_FX)
+               col->lb = col->ub = ccc->lb / sjj;
+            else
+               xassert(ccc != ccc);
+            col->coef = dir * ccc->coef * sjj;
+            for (aaa = ccc->ptr; aaa != NULL; aaa = aaa->c_next)
+               npp_add_aij(npp, link[aaa->row->i], col,
+                  aaa->row->rii * aaa->val * sjj);
+         }
+      }
+      xfree(link);
+      /* keep solution indicator and scaling option */
+      npp->sol = sol;
+      npp->scaling = scaling;
+      return;
+}
+
+void npp_build_prob(NPP *npp, glp_prob *prob)
+{     /* build resultant (preprocessed) problem */
+      NPPROW *row;
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int i, j, type, len, *ind;
+      double dir, *val;
+      glp_erase_prob(prob);
+      glp_set_prob_name(prob, npp->name);
+      glp_set_obj_name(prob, npp->obj);
+      glp_set_obj_dir(prob, npp->orig_dir);
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      glp_set_obj_coef(prob, 0, dir * npp->c0);
+      /* build rows */
+      for (row = npp->r_head; row != NULL; row = row->next)
+      {  row->temp = i = glp_add_rows(prob, 1);
+         glp_set_row_name(prob, i, row->name);
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+            type = GLP_FR;
+         else if (row->ub == +DBL_MAX)
+            type = GLP_LO;
+         else if (row->lb == -DBL_MAX)
+            type = GLP_UP;
+         else if (row->lb != row->ub)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_row_bnds(prob, i, type, row->lb, row->ub);
+      }
+      /* build columns and the constraint matrix */
+      ind = xcalloc(1+prob->m, sizeof(int));
+      val = xcalloc(1+prob->m, sizeof(double));
+      for (col = npp->c_head; col != NULL; col = col->next)
+      {  j = glp_add_cols(prob, 1);
+         glp_set_col_name(prob, j, col->name);
+#if 0
+         glp_set_col_kind(prob, j, col->kind);
+#else
+         glp_set_col_kind(prob, j, col->is_int ? GLP_IV : GLP_CV);
+#endif
+         if (col->lb == -DBL_MAX && col->ub == +DBL_MAX)
+            type = GLP_FR;
+         else if (col->ub == +DBL_MAX)
+            type = GLP_LO;
+         else if (col->lb == -DBL_MAX)
+            type = GLP_UP;
+         else if (col->lb != col->ub)
+            type = GLP_DB;
+         else
+            type = GLP_FX;
+         glp_set_col_bnds(prob, j, type, col->lb, col->ub);
+         glp_set_obj_coef(prob, j, dir * col->coef);
+         len = 0;
+         for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+         {  len++;
+            ind[len] = aij->row->temp;
+            val[len] = aij->val;
+         }
+         glp_set_mat_col(prob, j, len, ind, val);
+      }
+      xfree(ind);
+      xfree(val);
+      /* resultant problem has been built */
+      npp->m = prob->m;
+      npp->n = prob->n;
+      npp->nnz = prob->nnz;
+      npp->row_ref = xcalloc(1+npp->m, sizeof(int));
+      npp->col_ref = xcalloc(1+npp->n, sizeof(int));
+      for (row = npp->r_head, i = 0; row != NULL; row = row->next)
+         npp->row_ref[++i] = row->i;
+      for (col = npp->c_head, j = 0; col != NULL; col = col->next)
+         npp->col_ref[++j] = col->j;
+      /* transformed problem segment is no longer needed */
+      dmp_delete_pool(npp->pool), npp->pool = NULL;
+      npp->name = npp->obj = NULL;
+      npp->c0 = 0.0;
+      npp->r_head = npp->r_tail = NULL;
+      npp->c_head = npp->c_tail = NULL;
+      return;
+}
+
+void npp_postprocess(NPP *npp, glp_prob *prob)
+{     /* postprocess solution from the resultant problem */
+      GLPROW *row;
+      GLPCOL *col;
+      NPPTSE *tse;
+      int i, j, k;
+      double dir;
+      xassert(npp->orig_dir == prob->dir);
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      xassert(npp->m == prob->m);
+      xassert(npp->n == prob->n);
+      xassert(npp->nnz == prob->nnz);
+      /* copy solution status */
+      if (npp->sol == GLP_SOL)
+      {  npp->p_stat = prob->pbs_stat;
+         npp->d_stat = prob->dbs_stat;
+      }
+      else if (npp->sol == GLP_IPT)
+         npp->t_stat = prob->ipt_stat;
+      else if (npp->sol == GLP_MIP)
+         npp->i_stat = prob->mip_stat;
+      else
+         xassert(npp != npp);
+      /* allocate solution arrays */
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat == NULL)
+            npp->r_stat = xcalloc(1+npp->nrows, sizeof(char));
+         for (i = 1; i <= npp->nrows; i++)
+            npp->r_stat[i] = 0;
+         if (npp->c_stat == NULL)
+            npp->c_stat = xcalloc(1+npp->ncols, sizeof(char));
+         for (j = 1; j <= npp->ncols; j++)
+            npp->c_stat[j] = 0;
+      }
+#if 0
+      if (npp->r_prim == NULL)
+         npp->r_prim = xcalloc(1+npp->nrows, sizeof(double));
+      for (i = 1; i <= npp->nrows; i++)
+         npp->r_prim[i] = DBL_MAX;
+#endif
+      if (npp->c_value == NULL)
+         npp->c_value = xcalloc(1+npp->ncols, sizeof(double));
+      for (j = 1; j <= npp->ncols; j++)
+         npp->c_value[j] = DBL_MAX;
+      if (npp->sol != GLP_MIP)
+      {  if (npp->r_pi == NULL)
+            npp->r_pi = xcalloc(1+npp->nrows, sizeof(double));
+         for (i = 1; i <= npp->nrows; i++)
+            npp->r_pi[i] = DBL_MAX;
+#if 0
+         if (npp->c_dual == NULL)
+            npp->c_dual = xcalloc(1+npp->ncols, sizeof(double));
+         for (j = 1; j <= npp->ncols; j++)
+            npp->c_dual[j] = DBL_MAX;
+#endif
+      }
+      /* copy solution components from the resultant problem */
+      if (npp->sol == GLP_SOL)
+      {  for (i = 1; i <= npp->m; i++)
+         {  row = prob->row[i];
+            k = npp->row_ref[i];
+            npp->r_stat[k] = (char)row->stat;
+            /*npp->r_prim[k] = row->prim;*/
+            npp->r_pi[k] = dir * row->dual;
+         }
+         for (j = 1; j <= npp->n; j++)
+         {  col = prob->col[j];
+            k = npp->col_ref[j];
+            npp->c_stat[k] = (char)col->stat;
+            npp->c_value[k] = col->prim;
+            /*npp->c_dual[k] = dir * col->dual;*/
+         }
+      }
+      else if (npp->sol == GLP_IPT)
+      {  for (i = 1; i <= npp->m; i++)
+         {  row = prob->row[i];
+            k = npp->row_ref[i];
+            /*npp->r_prim[k] = row->pval;*/
+            npp->r_pi[k] = dir * row->dval;
+         }
+         for (j = 1; j <= npp->n; j++)
+         {  col = prob->col[j];
+            k = npp->col_ref[j];
+            npp->c_value[k] = col->pval;
+            /*npp->c_dual[k] = dir * col->dval;*/
+         }
+      }
+      else if (npp->sol == GLP_MIP)
+      {
+#if 0
+         for (i = 1; i <= npp->m; i++)
+         {  row = prob->row[i];
+            k = npp->row_ref[i];
+            /*npp->r_prim[k] = row->mipx;*/
+         }
+#endif
+         for (j = 1; j <= npp->n; j++)
+         {  col = prob->col[j];
+            k = npp->col_ref[j];
+            npp->c_value[k] = col->mipx;
+         }
+      }
+      else
+         xassert(npp != npp);
+      /* perform postprocessing to construct solution to the original
+         problem */
+      for (tse = npp->top; tse != NULL; tse = tse->link)
+      {  xassert(tse->func != NULL);
+         xassert(tse->func(npp, tse->info) == 0);
+      }
+      return;
+}
+
+void npp_unload_sol(NPP *npp, glp_prob *orig)
+{     /* store solution to the original problem */
+      GLPROW *row;
+      GLPCOL *col;
+      int i, j;
+      double dir;
+      xassert(npp->orig_dir == orig->dir);
+      if (npp->orig_dir == GLP_MIN)
+         dir = +1.0;
+      else if (npp->orig_dir == GLP_MAX)
+         dir = -1.0;
+      else
+         xassert(npp != npp);
+      xassert(npp->orig_m == orig->m);
+      xassert(npp->orig_n == orig->n);
+      xassert(npp->orig_nnz == orig->nnz);
+      if (npp->sol == GLP_SOL)
+      {  /* store basic solution */
+         orig->valid = 0;
+         orig->pbs_stat = npp->p_stat;
+         orig->dbs_stat = npp->d_stat;
+         orig->obj_val = orig->c0;
+         orig->some = 0;
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            row->stat = npp->r_stat[i];
+            if (!npp->scaling)
+            {  /*row->prim = npp->r_prim[i];*/
+               row->dual = dir * npp->r_pi[i];
+            }
+            else
+            {  /*row->prim = npp->r_prim[i] / row->rii;*/
+               row->dual = dir * npp->r_pi[i] * row->rii;
+            }
+            if (row->stat == GLP_BS)
+               row->dual = 0.0;
+            else if (row->stat == GLP_NL)
+            {  xassert(row->type == GLP_LO || row->type == GLP_DB);
+               row->prim = row->lb;
+            }
+            else if (row->stat == GLP_NU)
+            {  xassert(row->type == GLP_UP || row->type == GLP_DB);
+               row->prim = row->ub;
+            }
+            else if (row->stat == GLP_NF)
+            {  xassert(row->type == GLP_FR);
+               row->prim = 0.0;
+            }
+            else if (row->stat == GLP_NS)
+            {  xassert(row->type == GLP_FX);
+               row->prim = row->lb;
+            }
+            else
+               xassert(row != row);
+         }
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            col->stat = npp->c_stat[j];
+            if (!npp->scaling)
+            {  col->prim = npp->c_value[j];
+               /*col->dual = dir * npp->c_dual[j];*/
+            }
+            else
+            {  col->prim = npp->c_value[j] * col->sjj;
+               /*col->dual = dir * npp->c_dual[j] / col->sjj;*/
+            }
+            if (col->stat == GLP_BS)
+               col->dual = 0.0;
+#if 1
+            else if (col->stat == GLP_NL)
+            {  xassert(col->type == GLP_LO || col->type == GLP_DB);
+               col->prim = col->lb;
+            }
+            else if (col->stat == GLP_NU)
+            {  xassert(col->type == GLP_UP || col->type == GLP_DB);
+               col->prim = col->ub;
+            }
+            else if (col->stat == GLP_NF)
+            {  xassert(col->type == GLP_FR);
+               col->prim = 0.0;
+            }
+            else if (col->stat == GLP_NS)
+            {  xassert(col->type == GLP_FX);
+               col->prim = col->lb;
+            }
+            else
+               xassert(col != col);
+#endif
+            orig->obj_val += col->coef * col->prim;
+         }
+#if 1
+         /* compute primal values of inactive rows */
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            if (row->stat == GLP_BS)
+            {  GLPAIJ *aij;
+               double temp;
+               temp = 0.0;
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  temp += aij->val * aij->col->prim;
+               row->prim = temp;
+            }
+         }
+         /* compute reduced costs of active columns */
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            if (col->stat != GLP_BS)
+            {  GLPAIJ *aij;
+               double temp;
+               temp = col->coef;
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                  temp -= aij->val * aij->row->dual;
+               col->dual = temp;
+            }
+         }
+#endif
+      }
+      else if (npp->sol == GLP_IPT)
+      {  /* store interior-point solution */
+         orig->ipt_stat = npp->t_stat;
+         orig->ipt_obj = orig->c0;
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            if (!npp->scaling)
+            {  /*row->pval = npp->r_prim[i];*/
+               row->dval = dir * npp->r_pi[i];
+            }
+            else
+            {  /*row->pval = npp->r_prim[i] / row->rii;*/
+               row->dval = dir * npp->r_pi[i] * row->rii;
+            }
+         }
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            if (!npp->scaling)
+            {  col->pval = npp->c_value[j];
+               /*col->dval = dir * npp->c_dual[j];*/
+            }
+            else
+            {  col->pval = npp->c_value[j] * col->sjj;
+               /*col->dval = dir * npp->c_dual[j] / col->sjj;*/
+            }
+            orig->ipt_obj += col->coef * col->pval;
+         }
+#if 1
+         /* compute row primal values */
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            {  GLPAIJ *aij;
+               double temp;
+               temp = 0.0;
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  temp += aij->val * aij->col->pval;
+               row->pval = temp;
+            }
+         }
+         /* compute column dual values */
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            {  GLPAIJ *aij;
+               double temp;
+               temp = col->coef;
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                  temp -= aij->val * aij->row->dval;
+               col->dval = temp;
+            }
+         }
+#endif
+      }
+      else if (npp->sol == GLP_MIP)
+      {  /* store MIP solution */
+         xassert(!npp->scaling);
+         orig->mip_stat = npp->i_stat;
+         orig->mip_obj = orig->c0;
+#if 0
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            /*row->mipx = npp->r_prim[i];*/
+         }
+#endif
+         for (j = 1; j <= orig->n; j++)
+         {  col = orig->col[j];
+            col->mipx = npp->c_value[j];
+            if (col->kind == GLP_IV)
+               xassert(col->mipx == floor(col->mipx));
+            orig->mip_obj += col->coef * col->mipx;
+         }
+#if 1
+         /* compute row primal values */
+         for (i = 1; i <= orig->m; i++)
+         {  row = orig->row[i];
+            {  GLPAIJ *aij;
+               double temp;
+               temp = 0.0;
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  temp += aij->val * aij->col->mipx;
+               row->mipx = temp;
+            }
+         }
+#endif
+      }
+      else
+         xassert(npp != npp);
+      return;
+}
+
+void npp_delete_wksp(NPP *npp)
+{     /* delete LP/MIP preprocessor workspace */
+      if (npp->pool != NULL)
+         dmp_delete_pool(npp->pool);
+      if (npp->stack != NULL)
+         dmp_delete_pool(npp->stack);
+      if (npp->row_ref != NULL)
+         xfree(npp->row_ref);
+      if (npp->col_ref != NULL)
+         xfree(npp->col_ref);
+      if (npp->r_stat != NULL)
+         xfree(npp->r_stat);
+#if 0
+      if (npp->r_prim != NULL)
+         xfree(npp->r_prim);
+#endif
+      if (npp->r_pi != NULL)
+         xfree(npp->r_pi);
+      if (npp->c_stat != NULL)
+         xfree(npp->c_stat);
+      if (npp->c_value != NULL)
+         xfree(npp->c_value);
+#if 0
+      if (npp->c_dual != NULL)
+         xfree(npp->c_dual);
+#endif
+      xfree(npp);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpnpp02.c
===================================================================
--- deps/glpk/src/glpnpp02.c	(revision 9)
+++ deps/glpk/src/glpnpp02.c	(revision 9)
@@ -0,0 +1,1433 @@
+/* glpnpp02.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_free_row - process free (unbounded) row
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_free_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_free_row processes row p, which is free (i.e. has
+*  no finite bounds):
+*
+*     -inf < sum a[p,j] x[j] < +inf.                                 (1)
+*             j
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (1) cannot be active, so it is redundant and can be
+*  removed from the original problem.
+*
+*  Removing row p leads to removing a column of multiplier pi[p] for
+*  this row in the dual system. Since row p has no bounds, pi[p] = 0,
+*  so removing the column does not affect the dual solution.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In solution to the original problem row p is inactive constraint,
+*  so it is assigned status GLP_BS, and multiplier pi[p] is assigned
+*  zero value.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  In solution to the original problem row p is inactive constraint,
+*  so its multiplier pi[p] is assigned zero value.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct free_row
+{     /* free (unbounded) row */
+      int p;
+      /* row reference number */
+};
+
+static int rcv_free_row(NPP *npp, void *info);
+
+void npp_free_row(NPP *npp, NPPROW *p)
+{     /* process free (unbounded) row */
+      struct free_row *info;
+      /* the row must be free */
+      xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_free_row, sizeof(struct free_row));
+      info->p = p->i;
+      /* remove the row from the problem */
+      npp_del_row(npp, p);
+      return;
+}
+
+static int rcv_free_row(NPP *npp, void *_info)
+{     /* recover free (unbounded) row */
+      struct free_row *info = _info;
+      if (npp->sol == GLP_SOL)
+         npp->r_stat[info->p] = GLP_BS;
+      if (npp->sol != GLP_MIP)
+         npp->r_pi[info->p] = 0.0;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_geq_row - process row of 'not less than' type
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_geq_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_geq_row processes row p, which is 'not less than'
+*  inequality constraint:
+*
+*     L[p] <= sum a[p,j] x[j] (<= U[p]),                             (1)
+*              j
+*
+*  where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (1) can be replaced by equality constraint:
+*
+*     sum a[p,j] x[j] - s = L[p],                                    (2)
+*      j
+*
+*  where
+*
+*     0 <= s (<= U[p] - L[p])                                        (3)
+*
+*  is a non-negative surplus variable.
+*
+*  Since in the primal system there appears column s having the only
+*  non-zero coefficient in row p, in the dual system there appears a
+*  new row:
+*
+*     (-1) pi[p] + lambda = 0,                                       (4)
+*
+*  where (-1) is coefficient of column s in row p, pi[p] is multiplier
+*  of row p, lambda is multiplier of column q, 0 is coefficient of
+*  column s in the objective row.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status and status of column q in solution to the transformed
+*  problem as follows:
+*
+*     +--------------------------------------+------------------+
+*     |         Transformed problem          | Original problem |
+*     +-----------------+--------------------+------------------+
+*     | Status of row p | Status of column s | Status of row p  |
+*     +-----------------+--------------------+------------------+
+*     |     GLP_BS      |       GLP_BS       |       N/A        |
+*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
+*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_NL       |      GLP_NL      |
+*     |     GLP_NS      |       GLP_NU       |      GLP_NU      |
+*     +-----------------+--------------------+------------------+
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  1. In solution to the transformed problem row p and column q cannot
+*     be basic at the same time; otherwise the basis matrix would have
+*     two linear dependent columns: unity column of auxiliary variable
+*     of row p and unity column of variable s.
+*
+*  2. Though in the transformed problem row p is equality constraint,
+*     it may be basic due to primal degenerate solution.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct ineq_row
+{     /* inequality constraint row */
+      int p;
+      /* row reference number */
+      int s;
+      /* column reference number for slack/surplus variable */
+};
+
+static int rcv_geq_row(NPP *npp, void *info);
+
+void npp_geq_row(NPP *npp, NPPROW *p)
+{     /* process row of 'not less than' type */
+      struct ineq_row *info;
+      NPPCOL *s;
+      /* the row must have lower bound */
+      xassert(p->lb != -DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* create column for surplus variable */
+      s = npp_add_col(npp);
+      s->lb = 0.0;
+      s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+      /* and add it to the transformed problem */
+      npp_add_aij(npp, p, s, -1.0);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_geq_row, sizeof(struct ineq_row));
+      info->p = p->i;
+      info->s = s->j;
+      /* replace the row by equality constraint */
+      p->ub = p->lb;
+      return;
+}
+
+static int rcv_geq_row(NPP *npp, void *_info)
+{     /* recover row of 'not less than' type */
+      struct ineq_row *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+            {  npp_error();
+               return 1;
+            }
+            else if (npp->c_stat[info->s] == GLP_NL ||
+                     npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_BS;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->r_stat[info->p] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->r_stat[info->p] = GLP_NL;
+            else if (npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_NU;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_leq_row - process row of 'not greater than' type
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_leq_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_leq_row processes row p, which is 'not greater than'
+*  inequality constraint:
+*
+*     (L[p] <=) sum a[p,j] x[j] <= U[p],                             (1)
+*                j
+*
+*  where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (1) can be replaced by equality constraint:
+*
+*     sum a[p,j] x[j] + s = L[p],                                    (2)
+*      j
+*
+*  where
+*
+*     0 <= s (<= U[p] - L[p])                                        (3)
+*
+*  is a non-negative slack variable.
+*
+*  Since in the primal system there appears column s having the only
+*  non-zero coefficient in row p, in the dual system there appears a
+*  new row:
+*
+*     (+1) pi[p] + lambda = 0,                                       (4)
+*
+*  where (+1) is coefficient of column s in row p, pi[p] is multiplier
+*  of row p, lambda is multiplier of column q, 0 is coefficient of
+*  column s in the objective row.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status and status of column q in solution to the transformed
+*  problem as follows:
+*
+*     +--------------------------------------+------------------+
+*     |         Transformed problem          | Original problem |
+*     +-----------------+--------------------+------------------+
+*     | Status of row p | Status of column s | Status of row p  |
+*     +-----------------+--------------------+------------------+
+*     |     GLP_BS      |       GLP_BS       |       N/A        |
+*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
+*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
+*     |     GLP_NS      |       GLP_NL       |      GLP_NU      |
+*     |     GLP_NS      |       GLP_NU       |      GLP_NL      |
+*     +-----------------+--------------------+------------------+
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  1. In solution to the transformed problem row p and column q cannot
+*     be basic at the same time; otherwise the basis matrix would have
+*     two linear dependent columns: unity column of auxiliary variable
+*     of row p and unity column of variable s.
+*
+*  2. Though in the transformed problem row p is equality constraint,
+*     it may be basic due to primal degeneracy.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem
+*  is the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+static int rcv_leq_row(NPP *npp, void *info);
+
+void npp_leq_row(NPP *npp, NPPROW *p)
+{     /* process row of 'not greater than' type */
+      struct ineq_row *info;
+      NPPCOL *s;
+      /* the row must have upper bound */
+      xassert(p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* create column for slack variable */
+      s = npp_add_col(npp);
+      s->lb = 0.0;
+      s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
+      /* and add it to the transformed problem */
+      npp_add_aij(npp, p, s, +1.0);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_leq_row, sizeof(struct ineq_row));
+      info->p = p->i;
+      info->s = s->j;
+      /* replace the row by equality constraint */
+      p->lb = p->ub;
+      return;
+}
+
+static int rcv_leq_row(NPP *npp, void *_info)
+{     /* recover row of 'not greater than' type */
+      struct ineq_row *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+            {  npp_error();
+               return 1;
+            }
+            else if (npp->c_stat[info->s] == GLP_NL ||
+                     npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_BS;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->r_stat[info->p] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->r_stat[info->p] = GLP_NU;
+            else if (npp->c_stat[info->s] == GLP_NU)
+               npp->r_stat[info->p] = GLP_NL;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_free_col - process free (unbounded) column
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_free_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_free_col processes column q, which is free (i.e. has
+*  no finite bounds):
+*
+*     -oo < x[q] < +oo.                                              (1)
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Free (unbounded) variable can be replaced by the difference of two
+*  non-negative variables:
+*
+*     x[q] = s' - s'',   s', s'' >= 0.                               (2)
+*
+*  Assuming that in the transformed problem x[q] becomes s',
+*  transformation (2) causes new column s'' to appear, which differs
+*  from column s' only in the sign of coefficients in constraint and
+*  objective rows. Thus, if in the dual system the following row
+*  corresponds to column s':
+*
+*     sum a[i,q] pi[i] + lambda' = c[q],                             (3)
+*      i
+*
+*  the row which corresponds to column s'' is the following:
+*
+*     sum (-a[i,q]) pi[i] + lambda'' = -c[q].                        (4)
+*      i
+*
+*  Then from (3) and (4) it follows that:
+*
+*     lambda' + lambda'' = 0   =>   lambda' = lmabda'' = 0,          (5)
+*
+*  where lambda' and lambda'' are multipliers for columns s' and s'',
+*  resp.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  With respect to (5) status of column q in solution to the original
+*  problem is determined by statuses of columns s' and s'' in solution
+*  to the transformed problem as follows:
+*
+*     +--------------------------------------+------------------+
+*     |         Transformed problem          | Original problem |
+*     +------------------+-------------------+------------------+
+*     | Status of col s' | Status of col s'' | Status of col q  |
+*     +------------------+-------------------+------------------+
+*     |      GLP_BS      |      GLP_BS       |       N/A        |
+*     |      GLP_BS      |      GLP_NL       |      GLP_BS      |
+*     |      GLP_NL      |      GLP_BS       |      GLP_BS      |
+*     |      GLP_NL      |      GLP_NL       |      GLP_NF      |
+*     +------------------+-------------------+------------------+
+*
+*  Value of column q is computed with formula (2).
+*
+*  1. In solution to the transformed problem columns s' and s'' cannot
+*     be basic at the same time, because they differ only in the sign,
+*     hence, are linear dependent.
+*
+*  2. Though column q is free, it can be non-basic due to dual
+*     degeneracy.
+*
+*  3. If column q is integral, columns s' and s'' are also integral.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (2). */
+
+struct free_col
+{     /* free (unbounded) column */
+      int q;
+      /* column reference number for variables x[q] and s' */
+      int s;
+      /* column reference number for variable s'' */
+};
+
+static int rcv_free_col(NPP *npp, void *info);
+
+void npp_free_col(NPP *npp, NPPCOL *q)
+{     /* process free (unbounded) column */
+      struct free_col *info;
+      NPPCOL *s;
+      NPPAIJ *aij;
+      /* the column must be free */
+      xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
+      /* variable x[q] becomes s' */
+      q->lb = 0.0, q->ub = +DBL_MAX;
+      /* create variable s'' */
+      s = npp_add_col(npp);
+      s->is_int = q->is_int;
+      s->lb = 0.0, s->ub = +DBL_MAX;
+      /* duplicate objective coefficient */
+      s->coef = -q->coef;
+      /* duplicate column of the constraint matrix */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         npp_add_aij(npp, aij->row, s, -aij->val);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_free_col, sizeof(struct free_col));
+      info->q = q->j;
+      info->s = s->j;
+      return;
+}
+
+static int rcv_free_col(NPP *npp, void *_info)
+{     /* recover free (unbounded) column */
+      struct free_col *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+            {  npp_error();
+               return 1;
+            }
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_BS;
+            else
+            {  npp_error();
+               return -1;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NL)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->c_stat[info->q] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_NF;
+            else
+            {  npp_error();
+               return -1;
+            }
+         }
+         else
+         {  npp_error();
+            return -1;
+         }
+      }
+      /* compute value of x[q] with formula (2) */
+      npp->c_value[info->q] -= npp->c_value[info->s];
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_lbnd_col - process column with (non-zero) lower bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_lbnd_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_lbnd_col processes column q, which has (non-zero)
+*  lower bound:
+*
+*     l[q] <= x[q] (<= u[q]),                                        (1)
+*
+*  where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Column q can be replaced as follows:
+*
+*     x[q] = l[q] + s,                                               (2)
+*
+*  where
+*
+*     0 <= s (<= u[q] - l[q])                                        (3)
+*
+*  is a non-negative variable.
+*
+*  Substituting x[q] from (2) into the objective row, we have:
+*
+*     z = sum c[j] x[j] + c0 =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] s + c~0,
+*
+*  where
+*
+*     c~0 = c0 + c[q] l[q]                                           (4)
+*
+*  is the constant term of the objective in the transformed problem.
+*  Similarly, substituting x[q] into constraint row i, we have:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i]  ==>
+*             j!=q
+*
+*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+*              j!=q
+*
+*  where
+*
+*     L~[i] = L[i] - a[i,q] l[q],  U~[i] = U[i] - a[i,q] l[q]        (5)
+*
+*  are lower and upper bounds of row i in the transformed problem,
+*  resp.
+*
+*  Transformation (2) does not affect the dual system.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of column q in solution to the original problem is the same
+*  as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (2). */
+
+struct bnd_col
+{     /* bounded column */
+      int q;
+      /* column reference number for variables x[q] and s */
+      double bnd;
+      /* lower/upper bound l[q] or u[q] */
+};
+
+static int rcv_lbnd_col(NPP *npp, void *info);
+
+void npp_lbnd_col(NPP *npp, NPPCOL *q)
+{     /* process column with (non-zero) lower bound */
+      struct bnd_col *info;
+      NPPROW *i;
+      NPPAIJ *aij;
+      /* the column must have non-zero lower bound */
+      xassert(q->lb != 0.0);
+      xassert(q->lb != -DBL_MAX);
+      xassert(q->lb < q->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_lbnd_col, sizeof(struct bnd_col));
+      info->q = q->j;
+      info->bnd = q->lb;
+      /* substitute x[q] into objective row */
+      npp->c0 += q->coef * q->lb;
+      /* substitute x[q] into constraint rows */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+      {  i = aij->row;
+         if (i->lb == i->ub)
+            i->ub = (i->lb -= aij->val * q->lb);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= aij->val * q->lb;
+            if (i->ub != +DBL_MAX)
+               i->ub -= aij->val * q->lb;
+         }
+      }
+      /* column x[q] becomes column s */
+      if (q->ub != +DBL_MAX)
+         q->ub -= q->lb;
+      q->lb = 0.0;
+      return;
+}
+
+static int rcv_lbnd_col(NPP *npp, void *_info)
+{     /* recover column with (non-zero) lower bound */
+      struct bnd_col *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->c_stat[info->q] == GLP_BS ||
+             npp->c_stat[info->q] == GLP_NL ||
+             npp->c_stat[info->q] == GLP_NU)
+            npp->c_stat[info->q] = npp->c_stat[info->q];
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      /* compute value of x[q] with formula (2) */
+      npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_ubnd_col - process column with upper bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_ubnd_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_ubnd_col processes column q, which has upper bound:
+*
+*     (l[q] <=) x[q] <= u[q],                                        (1)
+*
+*  where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Column q can be replaced as follows:
+*
+*     x[q] = u[q] - s,                                               (2)
+*
+*  where
+*
+*     0 <= s (<= u[q] - l[q])                                        (3)
+*
+*  is a non-negative variable.
+*
+*  Substituting x[q] from (2) into the objective row, we have:
+*
+*     z = sum c[j] x[j] + c0 =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] - c[q] s + c~0,
+*
+*  where
+*
+*     c~0 = c0 + c[q] u[q]                                           (4)
+*
+*  is the constant term of the objective in the transformed problem.
+*  Similarly, substituting x[q] into constraint row i, we have:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i]  ==>
+*             j!=q
+*
+*     L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
+*              j!=q
+*
+*  where
+*
+*     L~[i] = L[i] - a[i,q] u[q],  U~[i] = U[i] - a[i,q] u[q]        (5)
+*
+*  are lower and upper bounds of row i in the transformed problem,
+*  resp.
+*
+*  Note that in the transformed problem coefficients c[q] and a[i,q]
+*  change their sign. Thus, the row of the dual system corresponding to
+*  column q:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q]                            (6)
+*      i
+*
+*  in the transformed problem becomes the following:
+*
+*     sum (-a[i,q]) pi[i] + lambda[s] = -c[q].                       (7)
+*      i
+*
+*  Therefore:
+*
+*     lambda[q] = - lambda[s],                                       (8)
+*
+*  where lambda[q] is multiplier for column q, lambda[s] is multiplier
+*  for column s.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  With respect to (8) status of column q in solution to the original
+*  problem is determined by status of column s in solution to the
+*  transformed problem as follows:
+*
+*     +-----------------------+--------------------+
+*     |  Status of column s   | Status of column q |
+*     | (transformed problem) | (original problem) |
+*     +-----------------------+--------------------+
+*     |        GLP_BS         |       GLP_BS       |
+*     |        GLP_NL         |       GLP_NU       |
+*     |        GLP_NU         |       GLP_NL       |
+*     +-----------------------+--------------------+
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (2).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (2). */
+
+static int rcv_ubnd_col(NPP *npp, void *info);
+
+void npp_ubnd_col(NPP *npp, NPPCOL *q)
+{     /* process column with upper bound */
+      struct bnd_col *info;
+      NPPROW *i;
+      NPPAIJ *aij;
+      /* the column must have upper bound */
+      xassert(q->ub != +DBL_MAX);
+      xassert(q->lb < q->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_ubnd_col, sizeof(struct bnd_col));
+      info->q = q->j;
+      info->bnd = q->ub;
+      /* substitute x[q] into objective row */
+      npp->c0 += q->coef * q->ub;
+      q->coef = -q->coef;
+      /* substitute x[q] into constraint rows */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+      {  i = aij->row;
+         if (i->lb == i->ub)
+            i->ub = (i->lb -= aij->val * q->ub);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= aij->val * q->ub;
+            if (i->ub != +DBL_MAX)
+               i->ub -= aij->val * q->ub;
+         }
+         aij->val = -aij->val;
+      }
+      /* column x[q] becomes column s */
+      if (q->lb != -DBL_MAX)
+         q->ub -= q->lb;
+      else
+         q->ub = +DBL_MAX;
+      q->lb = 0.0;
+      return;
+}
+
+static int rcv_ubnd_col(NPP *npp, void *_info)
+{     /* recover column with upper bound */
+      struct bnd_col *info = _info;
+      if (npp->sol == GLP_BS)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+            npp->c_stat[info->q] = GLP_BS;
+         else if (npp->c_stat[info->q] == GLP_NL)
+            npp->c_stat[info->q] = GLP_NU;
+         else if (npp->c_stat[info->q] == GLP_NU)
+            npp->c_stat[info->q] = GLP_NL;
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      /* compute value of x[q] with formula (2) */
+      npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_dbnd_col - process non-negative column with upper bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_dbnd_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_dbnd_col processes column q, which is non-negative
+*  and has upper bound:
+*
+*     0 <= x[q] <= u[q],                                             (1)
+*
+*  where u[q] > 0.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Upper bound of column q can be replaced by the following equality
+*  constraint:
+*
+*     x[q] + s = u[q],                                               (2)
+*
+*  where s >= 0 is a non-negative complement variable.
+*
+*  Since in the primal system along with new row (2) there appears a
+*  new column s having the only non-zero coefficient in this row, in
+*  the dual system there appears a new row:
+*
+*     (+1)pi + lambda[s] = 0,                                        (3)
+*
+*  where (+1) is coefficient at column s in row (2), pi is multiplier
+*  for row (2), lambda[s] is multiplier for column s, 0 is coefficient
+*  at column s in the objective row.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of column q in solution to the original problem is determined
+*  by its status and status of column s in solution to the transformed
+*  problem as follows:
+*
+*     +-----------------------------------+------------------+
+*     |         Transformed problem       | Original problem |
+*     +-----------------+-----------------+------------------+
+*     | Status of col q | Status of col s | Status of col q  |
+*     +-----------------+-----------------+------------------+
+*     |     GLP_BS      |     GLP_BS      |      GLP_BS      |
+*     |     GLP_BS      |     GLP_NL      |      GLP_NU      |
+*     |     GLP_NL      |     GLP_BS      |      GLP_NL      |
+*     |     GLP_NL      |     GLP_NL      |      GLP_NL (*)  |
+*     +-----------------+-----------------+------------------+
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  1. Formally, in solution to the transformed problem columns q and s
+*     cannot be non-basic at the same time, since the constraint (2)
+*     would be violated. However, if u[q] is close to zero, violation
+*     may be less than a working precision even if both columns q and s
+*     are non-basic. In this degenerate case row (2) can be only basic,
+*     i.e. non-active constraint (otherwise corresponding row of the
+*     basis matrix would be zero). This allows to pivot out auxiliary
+*     variable and pivot in column s, in which case the row becomes
+*     active while column s becomes basic.
+*
+*  2. If column q is integral, column s is also integral.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem. */
+
+struct dbnd_col
+{     /* double-bounded column */
+      int q;
+      /* column reference number for variable x[q] */
+      int s;
+      /* column reference number for complement variable s */
+};
+
+static int rcv_dbnd_col(NPP *npp, void *info);
+
+void npp_dbnd_col(NPP *npp, NPPCOL *q)
+{     /* process non-negative column with upper bound */
+      struct dbnd_col *info;
+      NPPROW *p;
+      NPPCOL *s;
+      /* the column must be non-negative with upper bound */
+      xassert(q->lb == 0.0);
+      xassert(q->ub > 0.0);
+      xassert(q->ub != +DBL_MAX);
+      /* create variable s */
+      s = npp_add_col(npp);
+      s->is_int = q->is_int;
+      s->lb = 0.0, s->ub = +DBL_MAX;
+      /* create equality constraint (2) */
+      p = npp_add_row(npp);
+      p->lb = p->ub = q->ub;
+      npp_add_aij(npp, p, q, +1.0);
+      npp_add_aij(npp, p, s, +1.0);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_dbnd_col, sizeof(struct dbnd_col));
+      info->q = q->j;
+      info->s = s->j;
+      /* remove upper bound of x[q] */
+      q->ub = +DBL_MAX;
+      return;
+}
+
+static int rcv_dbnd_col(NPP *npp, void *_info)
+{     /* recover non-negative column with upper bound */
+      struct dbnd_col *info = _info;
+      if (npp->sol == GLP_BS)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+         {  if (npp->c_stat[info->s] == GLP_BS)
+               npp->c_stat[info->q] = GLP_BS;
+            else if (npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_NU;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NL)
+         {  if (npp->c_stat[info->s] == GLP_BS ||
+                npp->c_stat[info->s] == GLP_NL)
+               npp->c_stat[info->q] = GLP_NL;
+            else
+            {  npp_error();
+               return 1;
+            }
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_fixed_col - process fixed column
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_fixed_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_fixed_col processes column q, which is fixed:
+*
+*     x[q] = s[q],                                                   (1)
+*
+*  where s[q] is a fixed column value.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  The value of a fixed column can be substituted into the objective
+*  and constraint rows that allows removing the column from the problem.
+*
+*  Substituting x[q] = s[q] into the objective row, we have:
+*
+*     z = sum c[j] x[j] + c0 =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c[q] s[q] + c0 =
+*         j!=q
+*
+*       = sum c[j] x[j] + c~0,
+*         j!=q
+*
+*  where
+*
+*     c~0 = c0 + c[q] s[q]                                           (2)
+*
+*  is the constant term of the objective in the transformed problem.
+*  Similarly, substituting x[q] = s[q] into constraint row i, we have:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i]  ==>
+*             j!=q
+*
+*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
+*              j!=q
+*
+*  where
+*
+*     L~[i] = L[i] - a[i,q] s[q],  U~[i] = U[i] - a[i,q] s[q]        (3)
+*
+*  are lower and upper bounds of row i in the transformed problem,
+*  resp.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Column q is assigned status GLP_NS and its value is assigned s[q].
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is assigned s[q].
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is assigned s[q]. */
+
+struct fixed_col
+{     /* fixed column */
+      int q;
+      /* column reference number for variable x[q] */
+      double s;
+      /* value, at which x[q] is fixed */
+};
+
+static int rcv_fixed_col(NPP *npp, void *info);
+
+void npp_fixed_col(NPP *npp, NPPCOL *q)
+{     /* process fixed column */
+      struct fixed_col *info;
+      NPPROW *i;
+      NPPAIJ *aij;
+      /* the column must be fixed */
+      xassert(q->lb == q->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_fixed_col, sizeof(struct fixed_col));
+      info->q = q->j;
+      info->s = q->lb;
+      /* substitute x[q] = s[q] into objective row */
+      npp->c0 += q->coef * q->lb;
+      /* substitute x[q] = s[q] into constraint rows */
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+      {  i = aij->row;
+         if (i->lb == i->ub)
+            i->ub = (i->lb -= aij->val * q->lb);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= aij->val * q->lb;
+            if (i->ub != +DBL_MAX)
+               i->ub -= aij->val * q->lb;
+         }
+      }
+      /* remove the column from the problem */
+      npp_del_col(npp, q);
+      return;
+}
+
+static int rcv_fixed_col(NPP *npp, void *_info)
+{     /* recover fixed column */
+      struct fixed_col *info = _info;
+      if (npp->sol == GLP_SOL)
+         npp->c_stat[info->q] = GLP_NS;
+      npp->c_value[info->q] = info->s;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_make_equality - process row with almost identical bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_make_equality(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_make_equality processes row p:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*              j
+*
+*  where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
+*  constraint.
+*
+*  RETURNS
+*
+*  0 - row bounds have not been changed;
+*
+*  1 - row has been replaced by equality constraint.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If bounds of row (1) are very close to each other:
+*
+*     U[p] - L[p] <= eps,                                            (2)
+*
+*  where eps is an absolute tolerance for row value, the row can be
+*  replaced by the following almost equivalent equiality constraint:
+*
+*     sum a[p,j] x[j] = b,                                           (3)
+*      j
+*
+*  where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
+*  to be very close to its nearest integer:
+*
+*     |b - floor(b + 0.5)| <= eps,                                   (4)
+*
+*  it is reasonable to use this nearest integer as the right-hand side.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status and the sign of its multiplier pi[p] in solution to
+*  the transformed problem as follows:
+*
+*     +-----------------------+---------+--------------------+
+*     |    Status of row p    | Sign of |  Status of row p   |
+*     | (transformed problem) |  pi[p]  | (original problem) |
+*     +-----------------------+---------+--------------------+
+*     |        GLP_BS         |  + / -  |       GLP_BS       |
+*     |        GLP_NS         |    +    |       GLP_NL       |
+*     |        GLP_NS         |    -    |       GLP_NU       |
+*     +-----------------------+---------+--------------------+
+*
+*  Value of row multiplier pi[p] in solution to the original problem is
+*  the same as in solution to the transformed problem.
+*
+*  RECOVERING INTERIOR POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem is
+*  the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct make_equality
+{     /* row with almost identical bounds */
+      int p;
+      /* row reference number */
+};
+
+static int rcv_make_equality(NPP *npp, void *info);
+
+int npp_make_equality(NPP *npp, NPPROW *p)
+{     /* process row with almost identical bounds */
+      struct make_equality *info;
+      double b, eps, nint;
+      /* the row must be double-sided inequality */
+      xassert(p->lb != -DBL_MAX);
+      xassert(p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* check row bounds */
+      eps = 1e-9 + 1e-12 * fabs(p->lb);
+      if (p->ub - p->lb > eps) return 0;
+      /* row bounds are very close to each other */
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_make_equality, sizeof(struct make_equality));
+      info->p = p->i;
+      /* compute right-hand side */
+      b = 0.5 * (p->ub + p->lb);
+      nint = floor(b + 0.5);
+      if (fabs(b - nint) <= eps) b = nint;
+      /* replace row p by almost equivalent equality constraint */
+      p->lb = p->ub = b;
+      return 1;
+}
+
+int rcv_make_equality(NPP *npp, void *_info)
+{     /* recover row with almost identical bounds */
+      struct make_equality *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+            npp->r_stat[info->p] = GLP_BS;
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  if (npp->r_pi[info->p] >= 0.0)
+               npp->r_stat[info->p] = GLP_NL;
+            else
+               npp->r_stat[info->p] = GLP_NU;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_make_fixed - process column with almost identical bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_make_fixed(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_make_fixed processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
+*  bounds.
+*
+*  RETURNS
+*
+*  0 - column bounds have not been changed;
+*
+*  1 - column has been fixed.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If bounds of column (1) are very close to each other:
+*
+*     u[q] - l[q] <= eps,                                            (2)
+*
+*  where eps is an absolute tolerance for column value, the column can
+*  be fixed:
+*
+*     x[q] = s[q],                                                   (3)
+*
+*  where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
+*  happens to be very close to its nearest integer:
+*
+*     |s[q] - floor(s[q] + 0.5)| <= eps,                             (4)
+*
+*  it is reasonable to use this nearest integer as the fixed value.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In the dual system of the original (as well as transformed) problem
+*  column q corresponds to the following row:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q].                           (5)
+*      i
+*
+*  Since multipliers pi[i] are known for all rows from solution to the
+*  transformed problem, formula (5) allows computing value of multiplier
+*  (reduced cost) for column q:
+*
+*     lambda[q] = c[q] - sum a[i,q] pi[i].                           (6)
+*                         i
+*
+*  Status of column q in solution to the original problem is determined
+*  by its status and the sign of its multiplier lambda[q] in solution to
+*  the transformed problem as follows:
+*
+*     +-----------------------+-----------+--------------------+
+*     |  Status of column q   |  Sign of  | Status of column q |
+*     | (transformed problem) | lambda[q] | (original problem) |
+*     +-----------------------+-----------+--------------------+
+*     |        GLP_BS         |   + / -   |       GLP_BS       |
+*     |        GLP_NS         |     +     |       GLP_NL       |
+*     |        GLP_NS         |     -     |       GLP_NU       |
+*     +-----------------------+-----------+--------------------+
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  RECOVERING INTERIOR POINT SOLUTION
+*
+*  Value of column q in solution to the original problem is the same as
+*  in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct make_fixed
+{     /* column with almost identical bounds */
+      int q;
+      /* column reference number */
+      double c;
+      /* objective coefficient at x[q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q] */
+};
+
+static int rcv_make_fixed(NPP *npp, void *info);
+
+int npp_make_fixed(NPP *npp, NPPCOL *q)
+{     /* process column with almost identical bounds */
+      struct make_fixed *info;
+      NPPAIJ *aij;
+      NPPLFE *lfe;
+      double s, eps, nint;
+      /* the column must be double-bounded */
+      xassert(q->lb != -DBL_MAX);
+      xassert(q->ub != +DBL_MAX);
+      xassert(q->lb < q->ub);
+      /* check column bounds */
+      eps = 1e-9 + 1e-12 * fabs(q->lb);
+      if (q->ub - q->lb > eps) return 0;
+      /* column bounds are very close to each other */
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_make_fixed, sizeof(struct make_fixed));
+      info->q = q->j;
+      info->c = q->coef;
+      info->ptr = NULL;
+      /* save column coefficients a[i,q] (needed for basic solution
+         only) */
+      if (npp->sol == GLP_SOL)
+      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = aij->row->i;
+            lfe->val = aij->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+      }
+      /* compute column fixed value */
+      s = 0.5 * (q->ub + q->lb);
+      nint = floor(s + 0.5);
+      if (fabs(s - nint) <= eps) s = nint;
+      /* make column q fixed */
+      q->lb = q->ub = s;
+      return 1;
+}
+
+static int rcv_make_fixed(NPP *npp, void *_info)
+{     /* recover column with almost identical bounds */
+      struct make_fixed *info = _info;
+      NPPLFE *lfe;
+      double lambda;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->c_stat[info->q] == GLP_BS)
+            npp->c_stat[info->q] = GLP_BS;
+         else if (npp->c_stat[info->q] == GLP_NS)
+         {  /* compute multiplier for column q with formula (6) */
+            lambda = info->c;
+            for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+               lambda -= lfe->val * npp->r_pi[lfe->ref];
+            /* assign status to non-basic column */
+            if (lambda >= 0.0)
+               npp->c_stat[info->q] = GLP_NL;
+            else
+               npp->c_stat[info->q] = GLP_NU;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/src/glpnpp03.c
===================================================================
--- deps/glpk/src/glpnpp03.c	(revision 9)
+++ deps/glpk/src/glpnpp03.c	(revision 9)
@@ -0,0 +1,2861 @@
+/* glpnpp03.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_empty_row - process empty row
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_empty_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_empty_row processes row p, which is empty, i.e.
+*  coefficients at all columns in this row are zero:
+*
+*     L[p] <= sum 0 x[j] <= U[p],                                    (1)
+*
+*  where L[p] <= U[p].
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - problem has no primal feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If the following conditions hold:
+*
+*     L[p] <= +eps,  U[p] >= -eps,                                   (2)
+*
+*  where eps is an absolute tolerance for row value, the row p is
+*  redundant. In this case it can be replaced by equivalent redundant
+*  row, which is free (unbounded), and then removed from the problem.
+*  Otherwise, the row p is infeasible and, thus, the problem has no
+*  primal feasible solution.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  See the routine npp_free_row.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  See the routine npp_free_row.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+int npp_empty_row(NPP *npp, NPPROW *p)
+{     /* process empty row */
+      double eps = 1e-3;
+      /* the row must be empty */
+      xassert(p->ptr == NULL);
+      /* check primal feasibility */
+      if (p->lb > +eps || p->ub < -eps)
+         return 1;
+      /* replace the row by equivalent free (unbounded) row */
+      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+      /* and process it */
+      npp_free_row(npp, p);
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_empty_col - process empty column
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_empty_col(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_empty_col processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] <= u[q], which is empty, i.e. has zero coefficients in
+*  all constraint rows.
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - problem has no dual feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  The row of the dual system corresponding to the empty column is the
+*  following:
+*
+*     sum 0 pi[i] + lambda[q] = c[q],                                (2)
+*      i
+*
+*  from which it follows that:
+*
+*     lambda[q] = c[q].                                              (3)
+*
+*  If the following condition holds:
+*
+*     c[q] < - eps,                                                  (4)
+*
+*  where eps is an absolute tolerance for column multiplier, the lower
+*  column bound l[q] must be active to provide dual feasibility (note
+*  that being preprocessed the problem is always minimization). In this
+*  case the column can be fixed on its lower bound and removed from the
+*  problem (if the column is integral, its bounds are also assumed to
+*  be integral). And if the column has no lower bound (l[q] = -oo), the
+*  problem has no dual feasible solution.
+*
+*  If the following condition holds:
+*
+*     c[q] > + eps,                                                  (5)
+*
+*  the upper column bound u[q] must be active to provide dual
+*  feasibility. In this case the column can be fixed on its upper bound
+*  and removed from the problem. And if the column has no upper bound
+*  (u[q] = +oo), the problem has no dual feasible solution.
+*
+*  Finally, if the following condition holds:
+*
+*     - eps <= c[q] <= +eps,                                         (6)
+*
+*  dual feasibility does not depend on a particular value of column q.
+*  In this case the column can be fixed either on its lower bound (if
+*  l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
+*  column is unbounded) and then removed from the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  See the routine npp_fixed_col. Having been recovered the column
+*  is assigned status GLP_NS. However, if actually it is not fixed
+*  (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
+*  GLP_NF depending on which bound it was fixed on transformation stage.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  See the routine npp_fixed_col.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  See the routine npp_fixed_col. */
+
+struct empty_col
+{     /* empty column */
+      int q;
+      /* column reference number */
+      char stat;
+      /* status in basic solution */
+};
+
+static int rcv_empty_col(NPP *npp, void *info);
+
+int npp_empty_col(NPP *npp, NPPCOL *q)
+{     /* process empty column */
+      struct empty_col *info;
+      double eps = 1e-3;
+      /* the column must be empty */
+      xassert(q->ptr == NULL);
+      /* check dual feasibility */
+      if (q->coef > +eps && q->lb == -DBL_MAX)
+         return 1;
+      if (q->coef < -eps && q->ub == +DBL_MAX)
+         return 1;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_empty_col, sizeof(struct empty_col));
+      info->q = q->j;
+      /* fix the column */
+      if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
+      {  /* free column */
+         info->stat = GLP_NF;
+         q->lb = q->ub = 0.0;
+      }
+      else if (q->ub == +DBL_MAX)
+lo:   {  /* column with lower bound */
+         info->stat = GLP_NL;
+         q->ub = q->lb;
+      }
+      else if (q->lb == -DBL_MAX)
+up:   {  /* column with upper bound */
+         info->stat = GLP_NU;
+         q->lb = q->ub;
+      }
+      else if (q->lb != q->ub)
+      {  /* double-bounded column */
+         if (q->coef >= +DBL_EPSILON) goto lo;
+         if (q->coef <= -DBL_EPSILON) goto up;
+         if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
+      }
+      else
+      {  /* fixed column */
+         info->stat = GLP_NS;
+      }
+      /* process fixed column */
+      npp_fixed_col(npp, q);
+      return 0;
+}
+
+static int rcv_empty_col(NPP *npp, void *_info)
+{     /* recover empty column */
+      struct empty_col *info = _info;
+      if (npp->sol == GLP_SOL)
+         npp->c_stat[info->q] = info->stat;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_value - process implied column value
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_value(NPP *npp, NPPCOL *q, double s);
+*
+*  DESCRIPTION
+*
+*  For column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], the routine npp_implied_value processes its
+*  implied value s[q]. If this implied value satisfies to the current
+*  column bounds and integrality condition, the routine fixes column q
+*  at the given point. Note that the column is kept in the problem in
+*  any case.
+*
+*  RETURNS
+*
+*  0 - column has been fixed;
+*
+*  1 - implied value violates to current column bounds;
+*
+*  2 - implied value violates integrality condition.
+*
+*  ALGORITHM
+*
+*  Implied column value s[q] satisfies to the current column bounds if
+*  the following condition holds:
+*
+*     l[q] - eps <= s[q] <= u[q] + eps,                              (2)
+*
+*  where eps is an absolute tolerance for column value. If the column
+*  is integral, the following condition also must hold:
+*
+*     |s[q] - floor(s[q]+0.5)| <= eps,                               (3)
+*
+*  where floor(s[q]+0.5) is the nearest integer to s[q].
+*
+*  If both condition (2) and (3) are satisfied, the column can be fixed
+*  at the value s[q], or, if it is integral, at floor(s[q]+0.5).
+*  Otherwise, if s[q] violates (2) or (3), the problem has no feasible
+*  solution.
+*
+*  Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
+*  fix the column at its lower or upper bound, resp. rather than at the
+*  implied value. */
+
+int npp_implied_value(NPP *npp, NPPCOL *q, double s)
+{     /* process implied column value */
+      double eps, nint;
+      xassert(npp == npp);
+      /* column must not be fixed */
+      xassert(q->lb < q->ub);
+      /* check integrality */
+      if (q->is_int)
+      {  nint = floor(s + 0.5);
+         if (fabs(s - nint) <= 1e-5)
+            s = nint;
+         else
+            return 2;
+      }
+      /* check current column lower bound */
+      if (q->lb != -DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+         if (s < q->lb - eps) return 1;
+         /* if s[q] is close to l[q], fix column at its lower bound
+            rather than at the implied value */
+         if (s < q->lb + 1e-3 * eps)
+         {  q->ub = q->lb;
+            return 0;
+         }
+      }
+      /* check current column upper bound */
+      if (q->ub != +DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+         if (s > q->ub + eps) return 1;
+         /* if s[q] is close to u[q], fix column at its upper bound
+            rather than at the implied value */
+         if (s > q->ub - 1e-3 * eps)
+         {  q->lb = q->ub;
+            return 0;
+         }
+      }
+      /* fix column at the implied value */
+      q->lb = q->ub = s;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_eq_singlet - process row singleton (equality constraint)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_eq_singlet(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_eq_singlet processes row p, which is equiality
+*  constraint having the only non-zero coefficient:
+*
+*     a[p,q] x[q] = b.                                               (1)
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - problem has no primal feasible solution;
+*
+*  2 - problem has no integer feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  The equality constraint defines implied value of column q:
+*
+*     x[q] = s[q] = b / a[p,q].                                      (2)
+*
+*  If the implied value s[q] satisfies to the column bounds (see the
+*  routine npp_implied_value), the column can be fixed at s[q] and
+*  removed from the problem. In this case row p becomes redundant, so
+*  it can be replaced by equivalent free row and also removed from the
+*  problem.
+*
+*  Note that the routine removes from the problem only row p. Column q
+*  becomes fixed, however, it is kept in the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In solution to the original problem row p is assigned status GLP_NS
+*  (active equality constraint), and column q is assigned status GLP_BS
+*  (basic column).
+*
+*  Multiplier for row p can be computed as follows. In the dual system
+*  of the original problem column q corresponds to the following row:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
+*      i
+*
+*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
+*     i!=p
+*
+*  Therefore:
+*
+*               1
+*     pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]),          (3)
+*             a[p,q]                     i!=q
+*
+*  where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
+*  i != p are known in solution to the transformed problem.
+*
+*  Value of column q in solution to the original problem is assigned
+*  its implied value s[q].
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Multiplier for row p is computed with formula (3). Value of column
+*  q is assigned its implied value s[q].
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is assigned its implied value s[q]. */
+
+struct eq_singlet
+{     /* row singleton (equality constraint) */
+      int p;
+      /* row reference number */
+      int q;
+      /* column reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      double c;
+      /* objective coefficient at x[q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_singlet(NPP *npp, void *info);
+
+int npp_eq_singlet(NPP *npp, NPPROW *p)
+{     /* process row singleton (equality constraint) */
+      struct eq_singlet *info;
+      NPPCOL *q;
+      NPPAIJ *aij;
+      NPPLFE *lfe;
+      int ret;
+      double s;
+      /* the row must be singleton equality constraint */
+      xassert(p->lb == p->ub);
+      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+      /* compute and process implied column value */
+      aij = p->ptr;
+      q = aij->col;
+      s = p->lb / aij->val;
+      ret = npp_implied_value(npp, q, s);
+      xassert(0 <= ret && ret <= 2);
+      if (ret != 0) return ret;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_eq_singlet, sizeof(struct eq_singlet));
+      info->p = p->i;
+      info->q = q->j;
+      info->apq = aij->val;
+      info->c = q->coef;
+      info->ptr = NULL;
+      /* save column coefficients a[i,q], i != p (not needed for MIP
+         solution) */
+      if (npp->sol != GLP_MIP)
+      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         {  if (aij->row == p) continue; /* skip a[p,q] */
+            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = aij->row->i;
+            lfe->val = aij->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+      }
+      /* remove the row from the problem */
+      npp_del_row(npp, p);
+      return 0;
+}
+
+static int rcv_eq_singlet(NPP *npp, void *_info)
+{     /* recover row singleton (equality constraint) */
+      struct eq_singlet *info = _info;
+      NPPLFE *lfe;
+      double temp;
+      if (npp->sol == GLP_SOL)
+      {  /* column q must be already recovered as GLP_NS */
+         if (npp->c_stat[info->q] != GLP_NS)
+         {  npp_error();
+            return 1;
+         }
+         npp->r_stat[info->p] = GLP_NS;
+         npp->c_stat[info->q] = GLP_BS;
+      }
+      if (npp->sol != GLP_MIP)
+      {  /* compute multiplier for row p with formula (3) */
+         temp = info->c;
+         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+            temp -= lfe->val * npp->r_pi[lfe->ref];
+         npp->r_pi[info->p] = temp / info->apq;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_lower - process implied column lower bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
+*
+*  DESCRIPTION
+*
+*  For column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], the routine npp_implied_lower processes its
+*  implied lower bound l'[q]. As the result the current column lower
+*  bound may increase. Note that the column is kept in the problem in
+*  any case.
+*
+*  RETURNS
+*
+*  0 - current column lower bound has not changed;
+*
+*  1 - current column lower bound has changed, but not significantly;
+*
+*  2 - current column lower bound has significantly changed;
+*
+*  3 - column has been fixed on its upper bound;
+*
+*  4 - implied lower bound violates current column upper bound.
+*
+*  ALGORITHM
+*
+*  If column q is integral, before processing its implied lower bound
+*  should be rounded up:
+*
+*              ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
+*     l'[q] := <                                                     (2)
+*              ( ceil(l'[q]),      otherwise
+*
+*  where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
+*  is smallest integer not less than l'[q], and eps is an absolute
+*  tolerance for column value.
+*
+*  Processing implied column lower bound l'[q] includes the following
+*  cases:
+*
+*  1) if l'[q] < l[q] + eps, implied lower bound is redundant;
+*
+*  2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
+*     l[q] can be strengthened by replacing it with l'[q]. If in this
+*     case new column lower bound becomes close to current column upper
+*     bound u[q], the column can be fixed on its upper bound;
+*
+*  3) if l'[q] > u[q] + eps, implied lower bound violates current
+*     column upper bound u[q], in which case the problem has no primal
+*     feasible solution. */
+
+int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
+{     /* process implied column lower bound */
+      int ret;
+      double eps, nint;
+      xassert(npp == npp);
+      /* column must not be fixed */
+      xassert(q->lb < q->ub);
+      /* implied lower bound must be finite */
+      xassert(l != -DBL_MAX);
+      /* if column is integral, round up l'[q] */
+      if (q->is_int)
+      {  nint = floor(l + 0.5);
+         if (fabs(l - nint) <= 1e-5)
+            l = nint;
+         else
+            l = ceil(l);
+      }
+      /* check current column lower bound */
+      if (q->lb != -DBL_MAX)
+      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
+         if (l < q->lb + eps)
+         {  ret = 0; /* redundant */
+            goto done;
+         }
+      }
+      /* check current column upper bound */
+      if (q->ub != +DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
+         if (l > q->ub + eps)
+         {  ret = 4; /* infeasible */
+            goto done;
+         }
+         /* if l'[q] is close to u[q], fix column at its upper bound */
+         if (l > q->ub - 1e-3 * eps)
+         {  q->lb = q->ub;
+            ret = 3; /* fixed */
+            goto done;
+         }
+      }
+      /* check if column lower bound changes significantly */
+      if (q->lb == -DBL_MAX)
+         ret = 2; /* significantly */
+      else if (q->is_int && l > q->lb + 0.5)
+         ret = 2; /* significantly */
+      else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
+         ret = 2; /* significantly */
+      else
+         ret = 1; /* not significantly */
+      /* set new column lower bound */
+      q->lb = l;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_upper - process implied column upper bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
+*
+*  DESCRIPTION
+*
+*  For column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], the routine npp_implied_upper processes its
+*  implied upper bound u'[q]. As the result the current column upper
+*  bound may decrease. Note that the column is kept in the problem in
+*  any case.
+*
+*  RETURNS
+*
+*  0 - current column upper bound has not changed;
+*
+*  1 - current column upper bound has changed, but not significantly;
+*
+*  2 - current column upper bound has significantly changed;
+*
+*  3 - column has been fixed on its lower bound;
+*
+*  4 - implied upper bound violates current column lower bound.
+*
+*  ALGORITHM
+*
+*  If column q is integral, before processing its implied upper bound
+*  should be rounded down:
+*
+*              ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
+*     u'[q] := <                                                     (2)
+*              ( floor(l'[q]),     otherwise
+*
+*  where floor(u'[q]+0.5) is the nearest integer to u'[q],
+*  floor(u'[q]) is largest integer not greater than u'[q], and eps is
+*  an absolute tolerance for column value.
+*
+*  Processing implied column upper bound u'[q] includes the following
+*  cases:
+*
+*  1) if u'[q] > u[q] - eps, implied upper bound is redundant;
+*
+*  2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
+*     u[q] can be strengthened by replacing it with u'[q]. If in this
+*     case new column upper bound becomes close to current column lower
+*     bound, the column can be fixed on its lower bound;
+*
+*  3) if u'[q] < l[q] - eps, implied upper bound violates current
+*     column lower bound l[q], in which case the problem has no primal
+*     feasible solution. */
+
+int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
+{     int ret;
+      double eps, nint;
+      xassert(npp == npp);
+      /* column must not be fixed */
+      xassert(q->lb < q->ub);
+      /* implied upper bound must be finite */
+      xassert(u != +DBL_MAX);
+      /* if column is integral, round down u'[q] */
+      if (q->is_int)
+      {  nint = floor(u + 0.5);
+         if (fabs(u - nint) <= 1e-5)
+            u = nint;
+         else
+            u = floor(u);
+      }
+      /* check current column upper bound */
+      if (q->ub != +DBL_MAX)
+      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
+         if (u > q->ub - eps)
+         {  ret = 0; /* redundant */
+            goto done;
+         }
+      }
+      /* check current column lower bound */
+      if (q->lb != -DBL_MAX)
+      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
+         if (u < q->lb - eps)
+         {  ret = 4; /* infeasible */
+            goto done;
+         }
+         /* if u'[q] is close to l[q], fix column at its lower bound */
+         if (u < q->lb + 1e-3 * eps)
+         {  q->ub = q->lb;
+            ret = 3; /* fixed */
+            goto done;
+         }
+      }
+      /* check if column upper bound changes significantly */
+      if (q->ub == +DBL_MAX)
+         ret = 2; /* significantly */
+      else if (q->is_int && u < q->ub - 0.5)
+         ret = 2; /* significantly */
+      else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
+         ret = 2; /* significantly */
+      else
+         ret = 1; /* not significantly */
+      /* set new column upper bound */
+      q->ub = u;
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_ineq_singlet - process row singleton (inequality constraint)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_ineq_singlet(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_ineq_singlet processes row p, which is inequality
+*  constraint having the only non-zero coefficient:
+*
+*     L[p] <= a[p,q] * x[q] <= U[p],                                 (1)
+*
+*  where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+*  RETURNS
+*
+*  0 - current column bounds have not changed;
+*
+*  1 - current column bounds have changed, but not significantly;
+*
+*  2 - current column bounds have significantly changed;
+*
+*  3 - column has been fixed on its lower or upper bound;
+*
+*  4 - problem has no primal feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Inequality constraint (1) defines implied bounds of column q:
+*
+*             (  L[p] / a[p,q],  if a[p,q] > 0
+*     l'[q] = <                                                      (2)
+*             (  U[p] / a[p,q],  if a[p,q] < 0
+*
+*             (  U[p] / a[p,q],  if a[p,q] > 0
+*     u'[q] = <                                                      (3)
+*             (  L[p] / a[p,q],  if a[p,q] < 0
+*
+*  If these implied bounds do not violate current bounds of column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (4)
+*
+*  they can be used to strengthen the current column bounds:
+*
+*     l[q] := max(l[q], l'[q]),                                      (5)
+*
+*     u[q] := min(u[q], u'[q]).                                      (6)
+*
+*  (See the routines npp_implied_lower and npp_implied_upper.)
+*
+*  Once bounds of row p (1) have been carried over column q, the row
+*  becomes redundant, so it can be replaced by equivalent free row and
+*  removed from the problem.
+*
+*  Note that the routine removes from the problem only row p. Column q,
+*  even it has been fixed, is kept in the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Note that the row in the dual system corresponding to column q is
+*  the following:
+*
+*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
+*      i
+*                                                                    (7)
+*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
+*     i!=p
+*
+*  where pi[i] for all i != p are known in solution to the transformed
+*  problem. Row p does not exist in the transformed problem, so it has
+*  zero multiplier there. This allows computing multiplier for column q
+*  in solution to the transformed problem:
+*
+*     lambda~[q] = c[q] - sum a[i,q] pi[i].                          (8)
+*                         i!=p
+*
+*  Let in solution to the transformed problem column q be non-basic
+*  with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
+*  bound be implied one l'[q]. From the original problem's standpoint
+*  this then means that actually the original column lower bound l[q]
+*  is inactive, and active is that row bound L[p] or U[p] that defines
+*  the implied bound l'[q] (2). In this case in solution to the
+*  original problem column q is assigned status GLP_BS while row p is
+*  assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
+*  Since now column q is basic, its multiplier lambda[q] is zero. This
+*  allows using (7) and (8) to find multiplier for row p in solution to
+*  the original problem:
+*
+*               1
+*     pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
+*             a[p,q]         i!=p
+*
+*  Now let in solution to the transformed problem column q be non-basic
+*  with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
+*  bound be implied one u'[q]. As in the previous case this then means
+*  that from the original problem's standpoint actually the original
+*  column upper bound u[q] is inactive, and active is that row bound
+*  L[p] or U[p] that defines the implied bound u'[q] (3). In this case
+*  in solution to the original problem column q is assigned status
+*  GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
+*  (if a[p,q] < 0), and its multiplier is computed with formula (9).
+*
+*  Strengthening bounds of column q according to (5) and (6) may make
+*  it fixed. Thus, if in solution to the transformed problem column q is
+*  non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
+*  column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
+*  column q has active upper bound (GLP_NU), reducing this case to two
+*  previous ones. If, however, lambda~[q] is close to zero or
+*  corresponding bound of row p does not exist (this may happen if
+*  lambda~[q] has wrong sign due to round-off errors, in which case it
+*  is expected to be close to zero, since solution is assumed to be dual
+*  feasible), column q can be assigned status GLP_BS (basic), and row p
+*  can be made active on its existing bound. In the latter case row
+*  multiplier pi[p] computed with formula (9) will be also close to
+*  zero, and dual feasibility will be kept.
+*
+*  In all other cases, namely, if in solution to the transformed
+*  problem column q is basic (GLP_BS), or non-basic with original lower
+*  bound l[q] active (GLP_NL), or non-basic with original upper bound
+*  u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
+*  the original problem status of column q remains unchanged, row p is
+*  assigned status GLP_BS, and its multiplier pi[p] is assigned zero
+*  value.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  First, value of multiplier for column q in solution to the original
+*  problem is computed with formula (8). If lambda~[q] > 0 and column q
+*  has implied lower bound, or if lambda~[q] < 0 and column q has
+*  implied upper bound, this means that from the original problem's
+*  standpoint actually row p has corresponding active bound, in which
+*  case its multiplier pi[p] is computed with formula (9). In other
+*  cases, when the sign of lambda~[q] corresponds to original bound of
+*  column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
+*  assigned zero value.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct ineq_singlet
+{     /* row singleton (inequality constraint) */
+      int p;
+      /* row reference number */
+      int q;
+      /* column reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      double c;
+      /* objective coefficient at x[q] */
+      double lb;
+      /* row lower bound */
+      double ub;
+      /* row upper bound */
+      char lb_changed;
+      /* this flag is set if column lower bound was changed */
+      char ub_changed;
+      /* this flag is set if column upper bound was changed */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_ineq_singlet(NPP *npp, void *info);
+
+int npp_ineq_singlet(NPP *npp, NPPROW *p)
+{     /* process row singleton (inequality constraint) */
+      struct ineq_singlet *info;
+      NPPCOL *q;
+      NPPAIJ *apq, *aij;
+      NPPLFE *lfe;
+      int lb_changed, ub_changed;
+      double ll, uu;
+      /* the row must be singleton inequality constraint */
+      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
+      /* compute implied column bounds */
+      apq = p->ptr;
+      q = apq->col;
+      xassert(q->lb < q->ub);
+      if (apq->val > 0.0)
+      {  ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
+         uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
+      }
+      else
+      {  ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
+         uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
+      }
+      /* process implied column lower bound */
+      if (ll == -DBL_MAX)
+         lb_changed = 0;
+      else
+      {  lb_changed = npp_implied_lower(npp, q, ll);
+         xassert(0 <= lb_changed && lb_changed <= 4);
+         if (lb_changed == 4) return 4; /* infeasible */
+      }
+      /* process implied column upper bound */
+      if (uu == +DBL_MAX)
+         ub_changed = 0;
+      else if (lb_changed == 3)
+      {  /* column was fixed on its upper bound due to l'[q] = u[q] */
+         /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
+         ub_changed = 0;
+      }
+      else
+      {  ub_changed = npp_implied_upper(npp, q, uu);
+         xassert(0 <= ub_changed && ub_changed <= 4);
+         if (ub_changed == 4) return 4; /* infeasible */
+      }
+      /* if neither lower nor upper column bound was changed, the row
+         is originally redundant and can be replaced by free row */
+      if (!lb_changed && !ub_changed)
+      {  p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+         npp_free_row(npp, p);
+         return 0;
+      }
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_ineq_singlet, sizeof(struct ineq_singlet));
+      info->p = p->i;
+      info->q = q->j;
+      info->apq = apq->val;
+      info->c = q->coef;
+      info->lb = p->lb;
+      info->ub = p->ub;
+      info->lb_changed = (char)lb_changed;
+      info->ub_changed = (char)ub_changed;
+      info->ptr = NULL;
+      /* save column coefficients a[i,q], i != p (not needed for MIP
+         solution) */
+      if (npp->sol != GLP_MIP)
+      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+         {  if (aij == apq) continue; /* skip a[p,q] */
+            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = aij->row->i;
+            lfe->val = aij->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+      }
+      /* remove the row from the problem */
+      npp_del_row(npp, p);
+      return lb_changed >= ub_changed ? lb_changed : ub_changed;
+}
+
+static int rcv_ineq_singlet(NPP *npp, void *_info)
+{     /* recover row singleton (inequality constraint) */
+      struct ineq_singlet *info = _info;
+      NPPLFE *lfe;
+      double lambda;
+      if (npp->sol == GLP_MIP) goto done;
+      /* compute lambda~[q] in solution to the transformed problem
+         with formula (8) */
+      lambda = info->c;
+      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+         lambda -= lfe->val * npp->r_pi[lfe->ref];
+      if (npp->sol == GLP_SOL)
+      {  /* recover basic solution */
+         if (npp->c_stat[info->q] == GLP_BS)
+         {  /* column q is basic, so row p is inactive */
+            npp->r_stat[info->p] = GLP_BS;
+            npp->r_pi[info->p] = 0.0;
+         }
+         else if (npp->c_stat[info->q] == GLP_NL)
+nl:      {  /* column q is non-basic with lower bound active */
+            if (info->lb_changed)
+            {  /* it is implied bound, so actually row p is active
+                  while column q is basic */
+               npp->r_stat[info->p] =
+                  (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+               npp->c_stat[info->q] = GLP_BS;
+               npp->r_pi[info->p] = lambda / info->apq;
+            }
+            else
+            {  /* it is original bound, so row p is inactive */
+               npp->r_stat[info->p] = GLP_BS;
+               npp->r_pi[info->p] = 0.0;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NU)
+nu:      {  /* column q is non-basic with upper bound active */
+            if (info->ub_changed)
+            {  /* it is implied bound, so actually row p is active
+                  while column q is basic */
+               npp->r_stat[info->p] =
+                  (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+               npp->c_stat[info->q] = GLP_BS;
+               npp->r_pi[info->p] = lambda / info->apq;
+            }
+            else
+            {  /* it is original bound, so row p is inactive */
+               npp->r_stat[info->p] = GLP_BS;
+               npp->r_pi[info->p] = 0.0;
+            }
+         }
+         else if (npp->c_stat[info->q] == GLP_NS)
+         {  /* column q is non-basic and fixed; note, however, that in
+               in the original problem it is non-fixed */
+            if (lambda > +1e-7)
+            {  if (info->apq > 0.0 && info->lb != -DBL_MAX ||
+                   info->apq < 0.0 && info->ub != +DBL_MAX ||
+                  !info->lb_changed)
+               {  /* either corresponding bound of row p exists or
+                     column q remains non-basic with its original lower
+                     bound active */
+                  npp->c_stat[info->q] = GLP_NL;
+                  goto nl;
+               }
+            }
+            if (lambda < -1e-7)
+            {  if (info->apq > 0.0 && info->ub != +DBL_MAX ||
+                   info->apq < 0.0 && info->lb != -DBL_MAX ||
+                  !info->ub_changed)
+               {  /* either corresponding bound of row p exists or
+                     column q remains non-basic with its original upper
+                     bound active */
+                  npp->c_stat[info->q] = GLP_NU;
+                  goto nu;
+               }
+            }
+            /* either lambda~[q] is close to zero, or corresponding
+               bound of row p does not exist, because lambda~[q] has
+               wrong sign due to round-off errors; in the latter case
+               lambda~[q] is also assumed to be close to zero; so, we
+               can make row p active on its existing bound and column q
+               basic; pi[p] will have wrong sign, but it also will be
+               close to zero (rarus casus of dual degeneracy) */
+            if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
+            {  /* row lower bound exists, but upper bound doesn't */
+               npp->r_stat[info->p] = GLP_NL;
+            }
+            else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
+            {  /* row upper bound exists, but lower bound doesn't */
+               npp->r_stat[info->p] = GLP_NU;
+            }
+            else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
+            {  /* both row lower and upper bounds exist */
+               /* to choose proper active row bound we should not use
+                  lambda~[q], because its value being close to zero is
+                  unreliable; so we choose that bound which provides
+                  primal feasibility for original constraint (1) */
+               if (info->apq * npp->c_value[info->q] <=
+                   0.5 * (info->lb + info->ub))
+                  npp->r_stat[info->p] = GLP_NL;
+               else
+                  npp->r_stat[info->p] = GLP_NU;
+            }
+            else
+            {  npp_error();
+               return 1;
+            }
+            npp->c_stat[info->q] = GLP_BS;
+            npp->r_pi[info->p] = lambda / info->apq;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      if (npp->sol == GLP_IPT)
+      {  /* recover interior-point solution */
+         if (lambda > +DBL_EPSILON && info->lb_changed ||
+             lambda < -DBL_EPSILON && info->ub_changed)
+         {  /* actually row p has corresponding active bound */
+            npp->r_pi[info->p] = lambda / info->apq;
+         }
+         else
+         {  /* either bounds of column q are both inactive or its
+               original bound is active */
+            npp->r_pi[info->p] = 0.0;
+         }
+      }
+done: return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_slack - process column singleton (implied slack variable)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_implied_slack(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_slack processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], having the only non-zero coefficient in row p,
+*  which is equality constraint:
+*
+*     sum a[p,j] x[j] + a[p,q] x[q] = b.                             (2)
+*     j!=q
+*
+*  PROBLEM TRANSFORMATION
+*
+*  (If x[q] is integral, this transformation must not be used.)
+*
+*  The term a[p,q] x[q] in constraint (2) can be considered as a slack
+*  variable that allows to carry bounds of column q over row p and then
+*  remove column q from the problem.
+*
+*  Constraint (2) can be written as follows:
+*
+*     sum a[p,j] x[j] = b - a[p,q] x[q].                             (3)
+*     j!=q
+*
+*  According to (1) constraint (3) is equivalent to the following
+*  inequality constraint:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (4)
+*             j!=q
+*
+*  where
+*
+*            ( b - a[p,q] u[q],  if a[p,q] > 0
+*     L[p] = <                                                       (5)
+*            ( b - a[p,q] l[q],  if a[p,q] < 0
+*
+*            ( b - a[p,q] l[q],  if a[p,q] > 0
+*     U[p] = <                                                       (6)
+*            ( b - a[p,q] u[q],  if a[p,q] < 0
+*
+*  From (2) it follows that:
+*
+*              1
+*     x[q] = ------ (b - sum a[p,j] x[j]).                           (7)
+*            a[p,q]      j!=q
+*
+*  In order to eliminate x[q] from the objective row we substitute it
+*  from (6) to that row:
+*
+*     z = sum c[j] x[j] + c[q] x[q] + c[0] =
+*         j!=q
+*                                 1
+*       = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
+*         j!=q                  a[p,q]      j!=q
+*
+*       = sum c~[j] x[j] + c~[0],
+*         j!=q
+*                         a[p,j]                     b
+*     c~[j] = c[j] - c[q] ------,  c~0 = c0 - c[q] ------            (8)
+*                         a[p,q]                   a[p,q]
+*
+*  are values of objective coefficients and constant term, resp., in
+*  the transformed problem.
+*
+*  Note that column q is column singleton, so in the dual system of the
+*  original problem it corresponds to the following row singleton:
+*
+*     a[p,q] pi[p] + lambda[q] = c[q].                               (9)
+*
+*  In the transformed problem row (9) would be the following:
+*
+*     a[p,q] pi~[p] + lambda[q] = c~[q] = 0.                        (10)
+*
+*  Subtracting (10) from (9) we have:
+*
+*     a[p,q] (pi[p] - pi~[p]) = c[q]
+*
+*  that gives the following formula to compute multiplier for row p in
+*  solution to the original problem using its value in solution to the
+*  transformed problem:
+*
+*     pi[p] = pi~[p] + c[q] / a[p,q].                               (11)
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of column q in solution to the original problem is defined
+*  by status of row p in solution to the transformed problem and the
+*  sign of coefficient a[p,q] in the original inequality constraint (2)
+*  as follows:
+*
+*     +-----------------------+---------+--------------------+
+*     |    Status of row p    | Sign of | Status of column q |
+*     | (transformed problem) | a[p,q]  | (original problem) |
+*     +-----------------------+---------+--------------------+
+*     |        GLP_BS         |  + / -  |       GLP_BS       |
+*     |        GLP_NL         |    +    |       GLP_NU       |
+*     |        GLP_NL         |    -    |       GLP_NL       |
+*     |        GLP_NU         |    +    |       GLP_NL       |
+*     |        GLP_NU         |    -    |       GLP_NU       |
+*     |        GLP_NF         |  + / -  |       GLP_NF       |
+*     +-----------------------+---------+--------------------+
+*
+*  Value of column q is computed with formula (7). Since originally row
+*  p is equality constraint, its status is assigned GLP_NS, and value of
+*  its multiplier pi[p] is computed with formula (11).
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of column q is computed with formula (7). Row multiplier value
+*  pi[p] is computed with formula (11).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  Value of column q is computed with formula (7). */
+
+struct implied_slack
+{     /* column singleton (implied slack variable) */
+      int p;
+      /* row reference number */
+      int q;
+      /* column reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      double b;
+      /* right-hand side of original equality constraint */
+      double c;
+      /* original objective coefficient at x[q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[p,j], j != q */
+};
+
+static int rcv_implied_slack(NPP *npp, void *info);
+
+void npp_implied_slack(NPP *npp, NPPCOL *q)
+{     /* process column singleton (implied slack variable) */
+      struct implied_slack *info;
+      NPPROW *p;
+      NPPAIJ *aij;
+      NPPLFE *lfe;
+      /* the column must be non-integral non-fixed singleton */
+      xassert(!q->is_int);
+      xassert(q->lb < q->ub);
+      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+      /* corresponding row must be equality constraint */
+      aij = q->ptr;
+      p = aij->row;
+      xassert(p->lb == p->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_implied_slack, sizeof(struct implied_slack));
+      info->p = p->i;
+      info->q = q->j;
+      info->apq = aij->val;
+      info->b = p->lb;
+      info->c = q->coef;
+      info->ptr = NULL;
+      /* save row coefficients a[p,j], j != q, and substitute x[q]
+         into the objective row */
+      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->col == q) continue; /* skip a[p,q] */
+         lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+         lfe->ref = aij->col->j;
+         lfe->val = aij->val;
+         lfe->next = info->ptr;
+         info->ptr = lfe;
+         aij->col->coef -= info->c * (aij->val / info->apq);
+      }
+      npp->c0 += info->c * (info->b / info->apq);
+      /* compute new row bounds */
+      if (info->apq > 0.0)
+      {  p->lb = (q->ub == +DBL_MAX ?
+            -DBL_MAX : info->b - info->apq * q->ub);
+         p->ub = (q->lb == -DBL_MAX ?
+            +DBL_MAX : info->b - info->apq * q->lb);
+      }
+      else
+      {  p->lb = (q->lb == -DBL_MAX ?
+            -DBL_MAX : info->b - info->apq * q->lb);
+         p->ub = (q->ub == +DBL_MAX ?
+            +DBL_MAX : info->b - info->apq * q->ub);
+      }
+      /* remove the column from the problem */
+      npp_del_col(npp, q);
+      return;
+}
+
+static int rcv_implied_slack(NPP *npp, void *_info)
+{     /* recover column singleton (implied slack variable) */
+      struct implied_slack *info = _info;
+      NPPLFE *lfe;
+      double temp;
+      if (npp->sol == GLP_SOL)
+      {  /* assign statuses to row p and column q */
+         if (npp->r_stat[info->p] == GLP_BS ||
+             npp->r_stat[info->p] == GLP_NF)
+            npp->c_stat[info->q] = npp->r_stat[info->p];
+         else if (npp->r_stat[info->p] == GLP_NL)
+            npp->c_stat[info->q] =
+               (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
+         else if (npp->r_stat[info->p] == GLP_NU)
+            npp->c_stat[info->q] =
+               (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
+         else
+         {  npp_error();
+            return 1;
+         }
+         npp->r_stat[info->p] = GLP_NS;
+      }
+      if (npp->sol != GLP_MIP)
+      {  /* compute multiplier for row p */
+         npp->r_pi[info->p] += info->c / info->apq;
+      }
+      /* compute value of column q */
+      temp = info->b;
+      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+         temp -= lfe->val * npp->c_value[lfe->ref];
+      npp->c_value[info->q] = temp / info->apq;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_free - process column singleton (implied free variable)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_free(NPP *npp, NPPCOL *q);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_free processes column q:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  having non-zero coefficient in the only row p, which is inequality
+*  constraint:
+*
+*     L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p],                 (2)
+*             j!=q
+*
+*  where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - column lower and/or upper bound(s) can be active;
+*
+*  2 - problem has no dual feasible solution.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Constraint (2) can be written as follows:
+*
+*     L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
+*            j!=q                                     j!=q
+*
+*  from which it follows that:
+*
+*     alfa <= a[p,q] x[q] <= beta,                                   (3)
+*
+*  where
+*
+*     alfa = inf(L[p] - sum a[p,j] x[j]) =
+*                       j!=q
+*
+*          = L[p] - sup sum a[p,j] x[j] =                            (4)
+*                       j!=q
+*
+*          = L[p] -  sum  a[p,j] u[j] -  sum  a[p,j] l[j],
+*                  j in Jp             j in Jn
+*
+*     beta = sup(L[p] - sum a[p,j] x[j]) =
+*                       j!=q
+*
+*          = L[p] - inf sum a[p,j] x[j] =                            (5)
+*                       j!=q
+*
+*          = L[p] -  sum  a[p,j] l[j] -  sum  a[p,j] u[j],
+*                  j in Jp             j in Jn
+*
+*     Jp = {j != q: a[p,j] > 0},  Jn = {j != q: a[p,j] < 0}.         (6)
+*
+*  Inequality (3) defines implied bounds of variable x[q]:
+*
+*     l'[q] <= x[q] <= u'[q],                                        (7)
+*
+*  where
+*
+*             ( alfa / a[p,q], if a[p,q] > 0
+*     l'[q] = <                                                     (8a)
+*             ( beta / a[p,q], if a[p,q] < 0
+*
+*             ( beta / a[p,q], if a[p,q] > 0
+*     u'[q] = <                                                     (8b)
+*             ( alfa / a[p,q], if a[p,q] < 0
+*
+*  Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
+*  an absolute tolerance for column value, column bounds (1) cannot be
+*  active, in which case column q can be replaced by equivalent free
+*  (unbounded) column.
+*
+*  Note that column q is column singleton, so in the dual system of the
+*  original problem it corresponds to the following row singleton:
+*
+*     a[p,q] pi[p] + lambda[q] = c[q],                               (9)
+*
+*  from which it follows that:
+*
+*     pi[p] = (c[q] - lambda[q]) / a[p,q].                          (10)
+*
+*  Let x[q] be implied free (unbounded) variable. Then column q can be
+*  only basic, so its multiplier lambda[q] is equal to zero, and from
+*  (10) we have:
+*
+*     pi[p] = c[q] / a[p,q].                                        (11)
+*
+*  There are possible three cases:
+*
+*  1) pi[p] < -eps, where eps is an absolute tolerance for row
+*     multiplier. In this case, to provide dual feasibility of the
+*     original problem, row p must be active on its lower bound, and
+*     if its lower bound does not exist (L[p] = -oo), the problem has
+*     no dual feasible solution;
+*
+*  2) pi[p] > +eps. In this case row p must be active on its upper
+*     bound, and if its upper bound does not exist (U[p] = +oo), the
+*     problem has no dual feasible solution;
+*
+*  3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
+*     bound of row p can be active, because this does not affect dual
+*     feasibility.
+*
+*  Thus, in all three cases original inequality constraint (2) can be
+*  replaced by equality constraint, where the right-hand side is either
+*  lower or upper bound of row p, and bounds of column q can be removed
+*  that makes it free (unbounded). (May note that this transformation
+*  can be followed by transformation "Column singleton (implied slack
+*  variable)" performed by the routine npp_implied_slack.)
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  Status of row p in solution to the original problem is determined
+*  by its status in solution to the transformed problem and its bound,
+*  which was choosen to be active:
+*
+*     +-----------------------+--------+--------------------+
+*     |    Status of row p    | Active | Status of row p    |
+*     | (transformed problem) | bound  | (original problem) |
+*     +-----------------------+--------+--------------------+
+*     |        GLP_BS         |  L[p]  |       GLP_BS       |
+*     |        GLP_BS         |  U[p]  |       GLP_BS       |
+*     |        GLP_NS         |  L[p]  |       GLP_NL       |
+*     |        GLP_NS         |  U[p]  |       GLP_NU       |
+*     +-----------------------+--------+--------------------+
+*
+*  Value of row multiplier pi[p] (as well as value of column q) in
+*  solution to the original problem is the same as in solution to the
+*  transformed problem.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of row multiplier pi[p] in solution to the original problem is
+*  the same as in solution to the transformed problem.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct implied_free
+{     /* column singleton (implied free variable) */
+      int p;
+      /* row reference number */
+      char stat;
+      /* row status:
+         GLP_NL - active constraint on lower bound
+         GLP_NU - active constraint on upper bound */
+};
+
+static int rcv_implied_free(NPP *npp, void *info);
+
+int npp_implied_free(NPP *npp, NPPCOL *q)
+{     /* process column singleton (implied free variable) */
+      struct implied_free *info;
+      NPPROW *p;
+      NPPAIJ *apq, *aij;
+      double alfa, beta, l, u, pi, eps;
+      /* the column must be non-fixed singleton */
+      xassert(q->lb < q->ub);
+      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
+      /* corresponding row must be inequality constraint */
+      apq = q->ptr;
+      p = apq->row;
+      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
+      xassert(p->lb < p->ub);
+      /* compute alfa */
+      alfa = p->lb;
+      if (alfa != -DBL_MAX)
+      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+         {  if (aij == apq) continue; /* skip a[p,q] */
+            if (aij->val > 0.0)
+            {  if (aij->col->ub == +DBL_MAX)
+               {  alfa = -DBL_MAX;
+                  break;
+               }
+               alfa -= aij->val * aij->col->ub;
+            }
+            else /* < 0.0 */
+            {  if (aij->col->lb == -DBL_MAX)
+               {  alfa = -DBL_MAX;
+                  break;
+               }
+               alfa -= aij->val * aij->col->lb;
+            }
+         }
+      }
+      /* compute beta */
+      beta = p->ub;
+      if (beta != +DBL_MAX)
+      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+         {  if (aij == apq) continue; /* skip a[p,q] */
+            if (aij->val > 0.0)
+            {  if (aij->col->lb == -DBL_MAX)
+               {  beta = +DBL_MAX;
+                  break;
+               }
+               beta -= aij->val * aij->col->lb;
+            }
+            else /* < 0.0 */
+            {  if (aij->col->ub == +DBL_MAX)
+               {  beta = +DBL_MAX;
+                  break;
+               }
+               beta -= aij->val * aij->col->ub;
+            }
+         }
+      }
+      /* compute implied column lower bound l'[q] */
+      if (apq->val > 0.0)
+         l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
+      else /* < 0.0 */
+         l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
+      /* compute implied column upper bound u'[q] */
+      if (apq->val > 0.0)
+         u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
+      else
+         u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
+      /* check if column lower bound l[q] can be active */
+      if (q->lb != -DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(q->lb);
+         if (l < q->lb - eps) return 1; /* yes, it can */
+      }
+      /* check if column upper bound u[q] can be active */
+      if (q->ub != +DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(q->ub);
+         if (u > q->ub + eps) return 1; /* yes, it can */
+      }
+      /* okay; make column q free (unbounded) */
+      q->lb = -DBL_MAX, q->ub = +DBL_MAX;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_implied_free, sizeof(struct implied_free));
+      info->p = p->i;
+      info->stat = -1;
+      /* compute row multiplier pi[p] */
+      pi = q->coef / apq->val;
+      /* check dual feasibility for row p */
+      if (pi > +DBL_EPSILON)
+      {  /* lower bound L[p] must be active */
+         if (p->lb != -DBL_MAX)
+nl:      {  info->stat = GLP_NL;
+            p->ub = p->lb;
+         }
+         else
+         {  if (pi > +1e-5) return 2; /* dual infeasibility */
+            /* take a chance on U[p] */
+            xassert(p->ub != +DBL_MAX);
+            goto nu;
+         }
+      }
+      else if (pi < -DBL_EPSILON)
+      {  /* upper bound U[p] must be active */
+         if (p->ub != +DBL_MAX)
+nu:      {  info->stat = GLP_NU;
+            p->lb = p->ub;
+         }
+         else
+         {  if (pi < -1e-5) return 2; /* dual infeasibility */
+            /* take a chance on L[p] */
+            xassert(p->lb != -DBL_MAX);
+            goto nl;
+         }
+      }
+      else
+      {  /* any bound (either L[p] or U[p]) can be made active  */
+         if (p->ub == +DBL_MAX)
+         {  xassert(p->lb != -DBL_MAX);
+            goto nl;
+         }
+         if (p->lb == -DBL_MAX)
+         {  xassert(p->ub != +DBL_MAX);
+            goto nu;
+         }
+         if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
+      }
+      return 0;
+}
+
+static int rcv_implied_free(NPP *npp, void *_info)
+{     /* recover column singleton (implied free variable) */
+      struct implied_free *info = _info;
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] == GLP_BS)
+            npp->r_stat[info->p] = GLP_BS;
+         else if (npp->r_stat[info->p] == GLP_NS)
+         {  xassert(info->stat == GLP_NL || info->stat == GLP_NU);
+            npp->r_stat[info->p] = info->stat;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_eq_doublet - process row doubleton (equality constraint)
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_eq_doublet processes row p, which is equality
+*  constraint having exactly two non-zero coefficients:
+*
+*     a[p,q] x[q] + a[p,r] x[r] = b.                                 (1)
+*
+*  As the result of processing one of columns q or r is eliminated from
+*  all other rows and, thus, becomes column singleton of type "implied
+*  slack variable". Row p is not changed and along with column q and r
+*  remains in the problem.
+*
+*  RETURNS
+*
+*  The routine npp_eq_doublet returns pointer to the descriptor of that
+*  column q or r which has been eliminated. If, due to some reason, the
+*  elimination was not performed, the routine returns NULL.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  First, we decide which column q or r will be eliminated. Let it be
+*  column q. Consider i-th constraint row, where column q has non-zero
+*  coefficient a[i,q] != 0:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i].                               (2)
+*              j
+*
+*  In order to eliminate column q from row (2) we subtract from it row
+*  (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
+*  transformed problem row (2) by its linear combination with row (1).
+*  This transformation changes only coefficients in columns q and r,
+*  and bounds of row i as follows:
+*
+*     a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0,                        (3)
+*
+*     a~[i,r] = a[i,r] - gamma[i] a[p,r],                            (4)
+*
+*       L~[i] = L[i] - gamma[i] b,                                   (5)
+*
+*       U~[i] = U[i] - gamma[i] b.                                   (6)
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  The transformation of the primal system of the original problem:
+*
+*     L <= A x <= U                                                  (7)
+*
+*  is equivalent to multiplying from the left a transformation matrix F
+*  by components of this primal system, which in the transformed problem
+*  becomes the following:
+*
+*     F L <= F A x <= F U  ==>  L~ <= A~x <= U~.                     (8)
+*
+*  The matrix F has the following structure:
+*
+*         ( 1           -gamma[1]            )
+*         (                                  )
+*         (    1        -gamma[2]            )
+*         (                                  )
+*         (      ...       ...               )
+*         (                                  )
+*     F = (          1  -gamma[p-1]          )                       (9)
+*         (                                  )
+*         (                 1                )
+*         (                                  )
+*         (             -gamma[p+1]  1       )
+*         (                                  )
+*         (                ...          ...  )
+*
+*  where its column containing elements -gamma[i] corresponds to row p
+*  of the primal system.
+*
+*  From (8) it follows that the dual system of the original problem:
+*
+*     A'pi + lambda = c,                                            (10)
+*
+*  in the transformed problem becomes the following:
+*
+*     A'F'inv(F')pi + lambda = c  ==>  (A~)'pi~ + lambda = c,       (11)
+*
+*  where:
+*
+*     pi~ = inv(F')pi                                               (12)
+*
+*  is the vector of row multipliers in the transformed problem. Thus:
+*
+*     pi = F'pi~.                                                   (13)
+*
+*  Therefore, as it follows from (13), value of multiplier for row p in
+*  solution to the original problem can be computed as follows:
+*
+*     pi[p] = pi~[p] - sum gamma[i] pi~[i],                         (14)
+*                       i
+*
+*  where pi~[i] = pi[i] is multiplier for row i (i != p).
+*
+*  Note that the statuses of all rows and columns are not changed.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Multiplier for row p in solution to the original problem is computed
+*  with formula (14).
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct eq_doublet
+{     /* row doubleton (equality constraint) */
+      int p;
+      /* row reference number */
+      double apq;
+      /* constraint coefficient a[p,q] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,q], i != p */
+};
+
+static int rcv_eq_doublet(NPP *npp, void *info);
+
+NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
+{     /* process row doubleton (equality constraint) */
+      struct eq_doublet *info;
+      NPPROW *i;
+      NPPCOL *q, *r;
+      NPPAIJ *apq, *apr, *aiq, *air, *next;
+      NPPLFE *lfe;
+      double gamma;
+      /* the row must be doubleton equality constraint */
+      xassert(p->lb == p->ub);
+      xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
+              p->ptr->r_next->r_next == NULL);
+      /* choose column to be eliminated */
+      {  NPPAIJ *a1, *a2;
+         a1 = p->ptr, a2 = a1->r_next;
+         if (fabs(a2->val) < 0.001 * fabs(a1->val))
+         {  /* only first column can be eliminated, because second one
+               has too small constraint coefficient */
+            apq = a1, apr = a2;
+         }
+         else if (fabs(a1->val) < 0.001 * fabs(a2->val))
+         {  /* only second column can be eliminated, because first one
+               has too small constraint coefficient */
+            apq = a2, apr = a1;
+         }
+         else
+         {  /* both columns are appropriate; choose that one which is
+               shorter to minimize fill-in */
+            if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
+            {  /* first column is shorter */
+               apq = a1, apr = a2;
+            }
+            else
+            {  /* second column is shorter */
+               apq = a2, apr = a1;
+            }
+         }
+      }
+      /* now columns q and r have been chosen */
+      q = apq->col, r = apr->col;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_eq_doublet, sizeof(struct eq_doublet));
+      info->p = p->i;
+      info->apq = apq->val;
+      info->ptr = NULL;
+      /* transform each row i (i != p), where a[i,q] != 0, to eliminate
+         column q */
+      for (aiq = q->ptr; aiq != NULL; aiq = next)
+      {  next = aiq->c_next;
+         if (aiq == apq) continue; /* skip row p */
+         i = aiq->row; /* row i to be transformed */
+         /* save constraint coefficient a[i,q] */
+         if (npp->sol != GLP_MIP)
+         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+            lfe->ref = i->i;
+            lfe->val = aiq->val;
+            lfe->next = info->ptr;
+            info->ptr = lfe;
+         }
+         /* find coefficient a[i,r] in row i */
+         for (air = i->ptr; air != NULL; air = air->r_next)
+            if (air->col == r) break;
+         /* if a[i,r] does not exist, create a[i,r] = 0 */
+         if (air == NULL)
+            air = npp_add_aij(npp, i, r, 0.0);
+         /* compute gamma[i] = a[i,q] / a[p,q] */
+         gamma = aiq->val / apq->val;
+         /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
+         /* new a[i,q] is exact zero due to elimnation; remove it from
+            row i */
+         npp_del_aij(npp, aiq);
+         /* compute new a[i,r] */
+         air->val -= gamma * apr->val;
+         /* if new a[i,r] is close to zero due to numeric cancelation,
+            remove it from row i */
+         if (fabs(air->val) <= 1e-10)
+            npp_del_aij(npp, air);
+         /* compute new lower and upper bounds of row i */
+         if (i->lb == i->ub)
+            i->lb = i->ub = (i->lb - gamma * p->lb);
+         else
+         {  if (i->lb != -DBL_MAX)
+               i->lb -= gamma * p->lb;
+            if (i->ub != +DBL_MAX)
+               i->ub -= gamma * p->lb;
+         }
+      }
+      return q;
+}
+
+static int rcv_eq_doublet(NPP *npp, void *_info)
+{     /* recover row doubleton (equality constraint) */
+      struct eq_doublet *info = _info;
+      NPPLFE *lfe;
+      double gamma, temp;
+      /* we assume that processing row p is followed by processing
+         column q as singleton of type "implied slack variable", in
+         which case row p must always be active equality constraint */
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] != GLP_NS)
+         {  npp_error();
+            return 1;
+         }
+      }
+      if (npp->sol != GLP_MIP)
+      {  /* compute value of multiplier for row p; see (14) */
+         temp = npp->r_pi[info->p];
+         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
+         {  gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
+            temp -= gamma * npp->r_pi[lfe->ref];
+         }
+         npp->r_pi[info->p] = temp;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_forcing_row - process forcing row
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_forcing_row(NPP *npp, NPPROW *p, int at);
+*
+*  DESCRIPTION
+*
+*  The routine npp_forcing row processes row p of general format:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*              j
+*
+*     l[j] <= x[j] <= u[j],                                          (2)
+*
+*  where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
+*  assumed that:
+*
+*  1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
+*     row upper bound (see below), eps is an absolute tolerance for row
+*     value;
+*
+*  2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
+*     row lower bound (see below).
+*
+*  RETURNS
+*
+*  0 - success;
+*
+*  1 - cannot fix columns due to too small constraint coefficients.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Implied lower and upper bounds of row (1) are determined by bounds
+*  of corresponding columns (variables) as follows:
+*
+*     L'[p] = inf sum a[p,j] x[j] =
+*                  j
+*                                                                    (3)
+*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
+*            j in Jp             j in Jn
+*
+*     U'[p] = sup sum a[p,j] x[j] =
+*                                                                    (4)
+*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
+*            j in Jp             j in Jn
+*
+*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
+*
+*  If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
+*  all variables take their boundary values as defined by (4):
+*
+*            ( u[j], if j in Jp
+*     x[j] = <                                                       (6)
+*            ( l[j], if j in Jn
+*
+*  Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
+*  only when all variables take their boundary values as defined by (3):
+*
+*            ( l[j], if j in Jp
+*     x[j] = <                                                       (7)
+*            ( u[j], if j in Jn
+*
+*  Condition (6) or (7) allows fixing all columns (variables x[j])
+*  in row (1) on their bounds and then removing them from the problem
+*  (see the routine npp_fixed_col). Due to this row p becomes redundant,
+*  so it can be replaced by equivalent free (unbounded) row and also
+*  removed from the problem (see the routine npp_free_row).
+*
+*  1. To apply this transformation row (1) should not have coefficients
+*     whose magnitude is too small, i.e. all a[p,j] should satisfy to
+*     the following condition:
+*
+*        |a[p,j]| >= eps * max(1, |a[p,k]|),                         (8)
+*                           k
+*     where eps is a relative tolerance for constraint coefficients.
+*     Otherwise, fixing columns may be numerically unreliable and may
+*     lead to wrong solution.
+*
+*  2. The routine fixes columns and remove bounds of row p, however,
+*     it does not remove the row and columns from the problem.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  In the transformed problem row p being inactive constraint is
+*  assigned status GLP_BS (as the result of transformation of free
+*  row), and all columns in this row are assigned status GLP_NS (as the
+*  result of transformation of fixed columns).
+*
+*  Note that in the dual system of the transformed (as well as original)
+*  problem every column j in row p corresponds to the following row:
+*
+*     sum  a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j],           (9)
+*     i!=p
+*
+*  from which it follows that:
+*
+*     lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p].           (10)
+*                        i!=p
+*
+*  In the transformed problem values of all multipliers pi[i] are known
+*  (including pi[i], whose value is zero, since row p is inactive).
+*  Thus, using formula (10) it is possible to compute values of
+*  multipliers lambda[j] for all columns in row p.
+*
+*  Note also that in the original problem all columns in row p are
+*  bounded, not fixed. So status GLP_NS assigned to every such column
+*  must be changed to GLP_NL or GLP_NU depending on which bound the
+*  corresponding column has been fixed. This status change may lead to
+*  dual feasibility violation for solution of the original problem,
+*  because now column multipliers must satisfy to the following
+*  condition:
+*
+*               ( >= 0, if status of column j is GLP_NL,
+*     lambda[j] <                                                   (11)
+*               ( <= 0, if status of column j is GLP_NU.
+*
+*  If this condition holds, solution to the original problem is the
+*  same as to the transformed problem. Otherwise, we have to perform
+*  one degenerate pivoting step of the primal simplex method to obtain
+*  dual feasible (hence, optimal) solution to the original problem as
+*  follows. If, on problem transformation, row p was made active on its
+*  lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
+*  and start increasing its multiplier pi[p]. Otherwise, if row p was
+*  made active on its upper bound (case at = 1), we change its status
+*  to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
+*  follows that:
+*
+*     delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p].    (12)
+*
+*  Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
+*  specified direction causes increasing lambda[j] for every column j
+*  assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
+*  for every column j assigned status GLP_NU (delta lambda[j] < 0). It
+*  is understood that once the last lambda[q], which violates condition
+*  (11), has reached zero, multipliers lambda[j] for all columns get
+*  valid signs. Such column q can be determined as follows. Let d[j] be
+*  initial value of lambda[j] (i.e. reduced cost of column j) in the
+*  transformed problem computed with formula (10) when pi[p] = 0. Then
+*  lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
+*  lambda[j] becomes zero if:
+*
+*     delta lambda[j] = - a[p,j] pi[p] = - d[j]  ==>
+*                                                                   (13)
+*     pi[p] = d[j] / a[p,j].
+*
+*  Therefore, the last column q, for which lambda[q] becomes zero, can
+*  be determined from the following condition:
+*
+*     |d[q] / a[p,q]| = max  |pi[p]| = max  |d[j] / a[p,j]|,        (14)
+*                      j in D         j in D
+*
+*  where D is a set of columns j whose, reduced costs d[j] have invalid
+*  signs, i.e. violate condition (11). (Thus, if D is empty, solution
+*  to the original problem is the same as solution to the transformed
+*  problem, and no correction is needed as was noticed above.) In
+*  solution to the original problem column q is assigned status GLP_BS,
+*  since it replaces column of auxiliary variable of row p (becoming
+*  active) in the basis, and multiplier for row p is assigned its new
+*  value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
+*  degeneracy values of all columns having non-zero coefficients in row
+*  p remain unchanged.
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  Value of multiplier pi[p] in solution to the original problem is
+*  corrected in the same way as for basic solution. Values of all
+*  columns having non-zero coefficients in row p remain unchanged.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct forcing_col
+{     /* column fixed on its bound by forcing row */
+      int j;
+      /* column reference number */
+      char stat;
+      /* original column status:
+         GLP_NL - fixed on lower bound
+         GLP_NU - fixed on upper bound */
+      double a;
+      /* constraint coefficient a[p,j] */
+      double c;
+      /* objective coefficient c[j] */
+      NPPLFE *ptr;
+      /* list of non-zero coefficients a[i,j], i != p */
+      struct forcing_col *next;
+      /* pointer to another column fixed by forcing row */
+};
+
+struct forcing_row
+{     /* forcing row */
+      int p;
+      /* row reference number */
+      char stat;
+      /* status assigned to the row if it becomes active:
+         GLP_NS - active equality constraint
+         GLP_NL - inequality constraint with lower bound active
+         GLP_NU - inequality constraint with upper bound active */
+      struct forcing_col *ptr;
+      /* list of all columns having non-zero constraint coefficient
+         a[p,j] in the forcing row */
+};
+
+static int rcv_forcing_row(NPP *npp, void *info);
+
+int npp_forcing_row(NPP *npp, NPPROW *p, int at)
+{     /* process forcing row */
+      struct forcing_row *info;
+      struct forcing_col *col = NULL;
+      NPPCOL *j;
+      NPPAIJ *apj, *aij;
+      NPPLFE *lfe;
+      double big;
+      xassert(at == 0 || at == 1);
+      /* determine maximal magnitude of the row coefficients */
+      big = 1.0;
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         if (big < fabs(apj->val)) big = fabs(apj->val);
+      /* if there are too small coefficients in the row, transformation
+         should not be applied */
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         if (fabs(apj->val) < 1e-7 * big) return 1;
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_forcing_row, sizeof(struct forcing_row));
+      info->p = p->i;
+      if (p->lb == p->ub)
+      {  /* equality constraint */
+         info->stat = GLP_NS;
+      }
+      else if (at == 0)
+      {  /* inequality constraint; case L[p] = U'[p] */
+         info->stat = GLP_NL;
+         xassert(p->lb != -DBL_MAX);
+      }
+      else /* at == 1 */
+      {  /* inequality constraint; case U[p] = L'[p] */
+         info->stat = GLP_NU;
+         xassert(p->ub != +DBL_MAX);
+      }
+      info->ptr = NULL;
+      /* scan the forcing row, fix columns at corresponding bounds, and
+         save column information (the latter is not needed for MIP) */
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+      {  /* column j has non-zero coefficient in the forcing row */
+         j = apj->col;
+         /* it must be non-fixed */
+         xassert(j->lb < j->ub);
+         /* allocate stack entry to save column information */
+         if (npp->sol != GLP_MIP)
+         {  col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
+            col->j = j->j;
+            col->stat = -1; /* will be set below */
+            col->a = apj->val;
+            col->c = j->coef;
+            col->ptr = NULL;
+            col->next = info->ptr;
+            info->ptr = col;
+         }
+         /* fix column j */
+         if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
+         {  /* at its lower bound */
+            if (npp->sol != GLP_MIP)
+               col->stat = GLP_NL;
+            xassert(j->lb != -DBL_MAX);
+            j->ub = j->lb;
+         }
+         else
+         {  /* at its upper bound */
+            if (npp->sol != GLP_MIP)
+               col->stat = GLP_NU;
+            xassert(j->ub != +DBL_MAX);
+            j->lb = j->ub;
+         }
+         /* save column coefficients a[i,j], i != p */
+         if (npp->sol != GLP_MIP)
+         {  for (aij = j->ptr; aij != NULL; aij = aij->c_next)
+            {  if (aij == apj) continue; /* skip a[p,j] */
+               lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
+               lfe->ref = aij->row->i;
+               lfe->val = aij->val;
+               lfe->next = col->ptr;
+               col->ptr = lfe;
+            }
+         }
+      }
+      /* make the row free (unbounded) */
+      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
+      return 0;
+}
+
+static int rcv_forcing_row(NPP *npp, void *_info)
+{     /* recover forcing row */
+      struct forcing_row *info = _info;
+      struct forcing_col *col, *piv;
+      NPPLFE *lfe;
+      double d, big, temp;
+      if (npp->sol == GLP_MIP) goto done;
+      /* initially solution to the original problem is the same as
+         to the transformed problem, where row p is inactive constraint
+         with pi[p] = 0, and all columns are non-basic */
+      if (npp->sol == GLP_SOL)
+      {  if (npp->r_stat[info->p] != GLP_BS)
+         {  npp_error();
+            return 1;
+         }
+         for (col = info->ptr; col != NULL; col = col->next)
+         {  if (npp->c_stat[col->j] != GLP_NS)
+            {  npp_error();
+               return 1;
+            }
+            npp->c_stat[col->j] = col->stat; /* original status */
+         }
+      }
+      /* compute reduced costs d[j] for all columns with formula (10)
+         and store them in col.c instead objective coefficients */
+      for (col = info->ptr; col != NULL; col = col->next)
+      {  d = col->c;
+         for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
+            d -= lfe->val * npp->r_pi[lfe->ref];
+         col->c = d;
+      }
+      /* consider columns j, whose multipliers lambda[j] has wrong
+         sign in solution to the transformed problem (where lambda[j] =
+         d[j]), and choose column q, whose multipler lambda[q] reaches
+         zero last on changing row multiplier pi[p]; see (14) */
+      piv = NULL, big = 0.0;
+      for (col = info->ptr; col != NULL; col = col->next)
+      {  d = col->c; /* d[j] */
+         temp = fabs(d / col->a);
+         if (col->stat == GLP_NL)
+         {  /* column j has active lower bound */
+            if (d < 0.0 && big < temp)
+               piv = col, big = temp;
+         }
+         else if (col->stat == GLP_NU)
+         {  /* column j has active upper bound */
+            if (d > 0.0 && big < temp)
+               piv = col, big = temp;
+         }
+         else
+         {  npp_error();
+            return 1;
+         }
+      }
+      /* if column q does not exist, no correction is needed */
+      if (piv != NULL)
+      {  /* correct solution; row p becomes active constraint while
+            column q becomes basic */
+         if (npp->sol == GLP_SOL)
+         {  npp->r_stat[info->p] = info->stat;
+            npp->c_stat[piv->j] = GLP_BS;
+         }
+         /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
+         npp->r_pi[info->p] = piv->c / piv->a;
+      }
+done: return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_analyze_row - perform general row analysis
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_analyze_row(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_analyze_row performs analysis of row p of general
+*  format:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*              j
+*
+*     l[j] <= x[j] <= u[j],                                          (2)
+*
+*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
+*
+*  RETURNS
+*
+*  0x?0 - row lower bound does not exist or is redundant;
+*
+*  0x?1 - row lower bound can be active;
+*
+*  0x?2 - row lower bound is a forcing bound;
+*
+*  0x0? - row upper bound does not exist or is redundant;
+*
+*  0x1? - row upper bound can be active;
+*
+*  0x2? - row upper bound is a forcing bound;
+*
+*  0x33 - row bounds are inconsistent with column bounds.
+*
+*  ALGORITHM
+*
+*  Analysis of row (1) is based on analysis of its implied lower and
+*  upper bounds, which are determined by bounds of corresponding columns
+*  (variables) as follows:
+*
+*     L'[p] = inf sum a[p,j] x[j] =
+*                  j
+*                                                                    (3)
+*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
+*            j in Jp             j in Jn
+*
+*     U'[p] = sup sum a[p,j] x[j] =
+*                                                                    (4)
+*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
+*            j in Jp             j in Jn
+*
+*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
+*
+*  (Note that bounds of all columns in row p are assumed to be correct,
+*  so L'[p] <= U'[p].)
+*
+*  Analysis of row lower bound L[p] includes the following cases:
+*
+*  1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
+*     value, row lower bound L[p] and implied row upper bound U'[p] are
+*     inconsistent, ergo, the problem has no primal feasible solution;
+*
+*  2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
+*     the row is a forcing row on its lower bound (see description of
+*     the routine npp_forcing_row);
+*
+*  3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
+*     conclusion does not account other rows in the problem);
+*
+*  4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
+*     it is redundant and can be removed (replaced by -oo).
+*
+*  Analysis of row upper bound U[p] is performed in a similar way and
+*  includes the following cases:
+*
+*  1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
+*     bound L'[p] are inconsistent, ergo the problem has no primal
+*     feasible solution;
+*
+*  2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
+*     the row is a forcing row on its upper bound (see description of
+*     the routine npp_forcing_row);
+*
+*  3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
+*     conclusion does not account other rows in the problem);
+*
+*  4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
+*     it is redundant and can be removed (replaced by +oo). */
+
+int npp_analyze_row(NPP *npp, NPPROW *p)
+{     /* perform general row analysis */
+      NPPAIJ *aij;
+      int ret = 0x00;
+      double l, u, eps;
+      xassert(npp == npp);
+      /* compute implied lower bound L'[p]; see (3) */
+      l = 0.0;
+      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->val > 0.0)
+         {  if (aij->col->lb == -DBL_MAX)
+            {  l = -DBL_MAX;
+               break;
+            }
+            l += aij->val * aij->col->lb;
+         }
+         else /* aij->val < 0.0 */
+         {  if (aij->col->ub == +DBL_MAX)
+            {  l = -DBL_MAX;
+               break;
+            }
+            l += aij->val * aij->col->ub;
+         }
+      }
+      /* compute implied upper bound U'[p]; see (4) */
+      u = 0.0;
+      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->val > 0.0)
+         {  if (aij->col->ub == +DBL_MAX)
+            {  u = +DBL_MAX;
+               break;
+            }
+            u += aij->val * aij->col->ub;
+         }
+         else /* aij->val < 0.0 */
+         {  if (aij->col->lb == -DBL_MAX)
+            {  u = +DBL_MAX;
+               break;
+            }
+            u += aij->val * aij->col->lb;
+         }
+      }
+      /* column bounds are assumed correct, so L'[p] <= U'[p] */
+      /* check if row lower bound is consistent */
+      if (p->lb != -DBL_MAX)
+      {  eps = 1e-3 + 1e-6 * fabs(p->lb);
+         if (p->lb - eps > u)
+         {  ret = 0x33;
+            goto done;
+         }
+      }
+      /* check if row upper bound is consistent */
+      if (p->ub != +DBL_MAX)
+      {  eps = 1e-3 + 1e-6 * fabs(p->ub);
+         if (p->ub + eps < l)
+         {  ret = 0x33;
+            goto done;
+         }
+      }
+      /* check if row lower bound can be active/forcing */
+      if (p->lb != -DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(p->lb);
+         if (p->lb - eps > l)
+         {  if (p->lb + eps <= u)
+               ret |= 0x01;
+            else
+               ret |= 0x02;
+         }
+      }
+      /* check if row upper bound can be active/forcing */
+      if (p->ub != +DBL_MAX)
+      {  eps = 1e-9 + 1e-12 * fabs(p->ub);
+         if (p->ub + eps < u)
+         {  /* check if the upper bound is forcing */
+            if (p->ub - eps >= l)
+               ret |= 0x10;
+            else
+               ret |= 0x20;
+         }
+      }
+done: return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_inactive_bound - remove row lower/upper inactive bound
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
+*
+*  DESCRIPTION
+*
+*  The routine npp_inactive_bound removes lower (if which = 0) or upper
+*  (if which = 1) bound of row p:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],
+*
+*  which (bound) is assumed to be redundant.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If which = 0, current lower bound L[p] of row p is assigned -oo.
+*  If which = 1, current upper bound U[p] of row p is assigned +oo.
+*
+*  RECOVERING BASIC SOLUTION
+*
+*  If in solution to the transformed problem row p is inactive
+*  constraint (GLP_BS), its status is not changed in solution to the
+*  original problem. Otherwise, status of row p in solution to the
+*  original problem is defined by its type before transformation and
+*  its status in solution to the transformed problem as follows:
+*
+*     +---------------------+-------+---------------+---------------+
+*     |        Row          | Flag  | Row status in | Row status in |
+*     |        type         | which | transfmd soln | original soln |
+*     +---------------------+-------+---------------+---------------+
+*     |     sum >= L[p]     |   0   |    GLP_NF     |    GLP_NL     |
+*     |     sum <= U[p]     |   1   |    GLP_NF     |    GLP_NU     |
+*     | L[p] <= sum <= U[p] |   0   |    GLP_NU     |    GLP_NU     |
+*     | L[p] <= sum <= U[p] |   1   |    GLP_NL     |    GLP_NL     |
+*     |  sum = L[p] = U[p]  |   0   |    GLP_NU     |    GLP_NS     |
+*     |  sum = L[p] = U[p]  |   1   |    GLP_NL     |    GLP_NS     |
+*     +---------------------+-------+---------------+---------------+
+*
+*  RECOVERING INTERIOR-POINT SOLUTION
+*
+*  None needed.
+*
+*  RECOVERING MIP SOLUTION
+*
+*  None needed. */
+
+struct inactive_bound
+{     /* row inactive bound */
+      int p;
+      /* row reference number */
+      char stat;
+      /* row status (if active constraint) */
+};
+
+static int rcv_inactive_bound(NPP *npp, void *info);
+
+void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
+{     /* remove row lower/upper inactive bound */
+      struct inactive_bound *info;
+      if (npp->sol == GLP_SOL)
+      {  /* create transformation stack entry */
+         info = npp_push_tse(npp,
+            rcv_inactive_bound, sizeof(struct inactive_bound));
+         info->p = p->i;
+         if (p->ub == +DBL_MAX)
+            info->stat = GLP_NL;
+         else if (p->lb == -DBL_MAX)
+            info->stat = GLP_NU;
+         else if (p->lb != p->ub)
+            info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
+         else
+            info->stat = GLP_NS;
+      }
+      /* remove row inactive bound */
+      if (which == 0)
+      {  xassert(p->lb != -DBL_MAX);
+         p->lb = -DBL_MAX;
+      }
+      else if (which == 1)
+      {  xassert(p->ub != +DBL_MAX);
+         p->ub = +DBL_MAX;
+      }
+      else
+         xassert(which != which);
+      return;
+}
+
+static int rcv_inactive_bound(NPP *npp, void *_info)
+{     /* recover row status */
+      struct inactive_bound *info = _info;
+      if (npp->sol != GLP_SOL)
+      {  npp_error();
+         return 1;
+      }
+      if (npp->r_stat[info->p] == GLP_BS)
+         npp->r_stat[info->p] = GLP_BS;
+      else
+         npp->r_stat[info->p] = info->stat;
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_bounds - determine implied column bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_implied_bounds(NPP *npp, NPPROW *p);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_bounds inspects general row (constraint) p:
+*
+*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
+*
+*     l[j] <= x[j] <= u[j],                                          (2)
+*
+*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
+*  implied bounds of columns (variables x[j]) in this row.
+*
+*  The routine stores implied column bounds l'[j] and u'[j] in column
+*  descriptors (NPPCOL); it does not change current column bounds l[j]
+*  and u[j]. (Implied column bounds can be then used to strengthen the
+*  current column bounds; see the routines npp_implied_lower and
+*  npp_implied_upper).
+*
+*  ALGORITHM
+*
+*  Current column bounds (2) define implied lower and upper bounds of
+*  row (1) as follows:
+*
+*     L'[p] = inf sum a[p,j] x[j] =
+*                  j
+*                                                                    (3)
+*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
+*            j in Jp             j in Jn
+*
+*     U'[p] = sup sum a[p,j] x[j] =
+*                                                                    (4)
+*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
+*            j in Jp             j in Jn
+*
+*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
+*
+*  (Note that bounds of all columns in row p are assumed to be correct,
+*  so L'[p] <= U'[p].)
+*
+*  If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
+*  row (1) can be active, in which case such row defines implied bounds
+*  of its variables.
+*
+*  Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
+*  Consider a case when row lower bound can be active (L[p] > L'[p]):
+*
+*     sum a[p,j] x[j] >= L[p]  ==>
+*      j
+*
+*     sum a[p,j] x[j] + a[p,k] x[k] >= L[p]  ==>
+*     j!=k
+*                                                                    (6)
+*     a[p,k] x[k] >= L[p] - sum a[p,j] x[j]  ==>
+*                           j!=k
+*
+*     a[p,k] x[k] >= L[p,k],
+*
+*  where
+*
+*     L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
+*                         j!=k
+*
+*            = L[p] - sup sum a[p,j] x[j] =                          (7)
+*                         j!=k
+*
+*            = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
+*                    j in Jp\{k}       j in Jn\{k}
+*
+*  Thus:
+*
+*     x[k] >= l'[k] = L[p,k] / a[p,k],  if a[p,k] > 0,               (8)
+*
+*     x[k] <= u'[k] = L[p,k] / a[p,k],  if a[p,k] < 0.               (9)
+*
+*  where l'[k] and u'[k] are implied lower and upper bounds of variable
+*  x[k], resp.
+*
+*  Now consider a similar case when row upper bound can be active
+*  (U[p] < U'[p]):
+*
+*     sum a[p,j] x[j] <= U[p]  ==>
+*      j
+*
+*     sum a[p,j] x[j] + a[p,k] x[k] <= U[p]  ==>
+*     j!=k
+*                                                                   (10)
+*     a[p,k] x[k] <= U[p] - sum a[p,j] x[j]  ==>
+*                           j!=k
+*
+*     a[p,k] x[k] <= U[p,k],
+*
+*  where:
+*
+*     U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
+*                         j!=k
+*
+*            = U[p] - inf sum a[p,j] x[j] =                         (11)
+*                         j!=k
+*
+*            = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
+*                    j in Jp\{k}       j in Jn\{k}
+*
+*  Thus:
+*
+*     x[k] <= u'[k] = U[p,k] / a[p,k],  if a[p,k] > 0,              (12)
+*
+*     x[k] >= l'[k] = U[p,k] / a[p,k],  if a[p,k] < 0.              (13)
+*
+*  Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
+*  must not be too small in magnitude relatively to other non-zero
+*  coefficients in row (1), i.e. the following condition must hold:
+*
+*     |a[p,k]| >= eps * max(1, |a[p,j]|),                           (14)
+*                        j
+*
+*  where eps is a relative tolerance for constraint coefficients.
+*  Otherwise the implied column bounds can be numerical inreliable. For
+*  example, using formula (8) for the following inequality constraint:
+*
+*     1e-12 x1 - x2 - x3 >= 0,
+*
+*  where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
+*  conclusion that x1 >= 0.
+*
+*  Using formulae (8), (9), (12), and (13) to compute implied bounds
+*  for one variable requires |J| operations, where J = {j: a[p,j] != 0},
+*  because this needs computing L[p,k] and U[p,k]. Thus, computing
+*  implied bounds for all variables in row (1) would require |J|^2
+*  operations, that is not a good technique. However, the total number
+*  of operations can be reduced to |J| as follows.
+*
+*  Let a[p,k] > 0. Then from (7) and (11) we have:
+*
+*     L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
+*
+*            = L[p] - U'[p] + a[p,k] u[k],
+*
+*     U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
+*
+*            = U[p] - L'[p] + a[p,k] l[k],
+*
+*  where L'[p] and U'[p] are implied row lower and upper bounds defined
+*  by formulae (3) and (4). Substituting these expressions into (8) and
+*  (12) gives:
+*
+*     l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k],     (15)
+*
+*     u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k].     (16)
+*
+*  Similarly, if a[p,k] < 0, according to (7) and (11) we have:
+*
+*     L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
+*
+*            = L[p] - U'[p] + a[p,k] l[k],
+*
+*     U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
+*
+*            = U[p] - L'[p] + a[p,k] u[k],
+*
+*  and substituting these expressions into (8) and (12) gives:
+*
+*     l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k],     (17)
+*
+*     u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k].     (18)
+*
+*  Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
+*  exist. However, if for some variable x[j] it happens that l[j] = -oo
+*  and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
+*  a[p,j] < 0) are undefined. Consider, therefore, the most general
+*  situation, when some column bounds (2) may not exist.
+*
+*  Let:
+*
+*     J' = {j : (a[p,j] > 0 and l[j] = -oo) or
+*                                                                   (19)
+*               (a[p,j] < 0 and u[j] = +oo)}.
+*
+*  Then (assuming that row upper bound U[p] can be active) the following
+*  three cases are possible:
+*
+*  1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
+*     in row (1) we can use formulae (16) and (17);
+*
+*  2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
+*     so for variable x[k] we can use formulae (12) and (13). Note that
+*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
+*     or u'[j] = +oo (if a[p,j] > 0);
+*
+*  3) |J'| > 1. In this case for all variables x[j] in row [1] we have
+*     l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
+*
+*  Similarly, let:
+*
+*     J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
+*                                                                   (20)
+*                (a[p,j] < 0 and l[j] = -oo)}.
+*
+*  Then (assuming that row lower bound L[p] can be active) the following
+*  three cases are possible:
+*
+*  1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
+*     in row (1) we can use formulae (15) and (18);
+*
+*  2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
+*     so for variable x[k] we can use formulae (8) and (9). Note that
+*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
+*     or u'[j] = +oo (if a[p,j] < 0);
+*
+*  3) |J''| > 1. In this case for all variables x[j] in row (1) we have
+*     l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
+
+void npp_implied_bounds(NPP *npp, NPPROW *p)
+{     NPPAIJ *apj, *apk;
+      double big, eps, temp;
+      xassert(npp == npp);
+      /* initialize implied bounds for all variables and determine
+         maximal magnitude of row coefficients a[p,j] */
+      big = 1.0;
+      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+      {  apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
+         if (big < fabs(apj->val)) big = fabs(apj->val);
+      }
+      eps = 1e-6 * big;
+      /* process row lower bound (assuming that it can be active) */
+      if (p->lb != -DBL_MAX)
+      {  apk = NULL;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
+                apj->val < 0.0 && apj->col->lb == -DBL_MAX)
+            {  if (apk == NULL)
+                  apk = apj;
+               else
+                  goto skip1;
+            }
+         }
+         /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
+         temp = p->lb;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj == apk)
+               /* skip a[p,k] */;
+            else if (apj->val > 0.0)
+               temp -= apj->val * apj->col->ub;
+            else /* apj->val < 0.0 */
+               temp -= apj->val * apj->col->lb;
+         }
+         /* compute column implied bounds */
+         if (apk == NULL)
+         {  /* temp = L[p] - U'[p] */
+            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+            {  if (apj->val >= +eps)
+               {  /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
+                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
+               }
+               else if (apj->val <= -eps)
+               {  /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
+                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
+               }
+            }
+         }
+         else
+         {  /* temp = L[p,k] */
+            if (apk->val >= +eps)
+            {  /* l'[k] := L[p,k] / a[p,k] */
+               apk->col->ll.ll = temp / apk->val;
+            }
+            else if (apk->val <= -eps)
+            {  /* u'[k] := L[p,k] / a[p,k] */
+               apk->col->uu.uu = temp / apk->val;
+            }
+         }
+skip1:   ;
+      }
+      /* process row upper bound (assuming that it can be active) */
+      if (p->ub != +DBL_MAX)
+      {  apk = NULL;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
+                apj->val < 0.0 && apj->col->ub == +DBL_MAX)
+            {  if (apk == NULL)
+                  apk = apj;
+               else
+                  goto skip2;
+            }
+         }
+         /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
+         temp = p->ub;
+         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+         {  if (apj == apk)
+               /* skip a[p,k] */;
+            else if (apj->val > 0.0)
+               temp -= apj->val * apj->col->lb;
+            else /* apj->val < 0.0 */
+               temp -= apj->val * apj->col->ub;
+         }
+         /* compute column implied bounds */
+         if (apk == NULL)
+         {  /* temp = U[p] - L'[p] */
+            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
+            {  if (apj->val >= +eps)
+               {  /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
+                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
+               }
+               else if (apj->val <= -eps)
+               {  /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
+                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
+               }
+            }
+         }
+         else
+         {  /* temp = U[p,k] */
+            if (apk->val >= +eps)
+            {  /* u'[k] := U[p,k] / a[p,k] */
+               apk->col->uu.uu = temp / apk->val;
+            }
+            else if (apk->val <= -eps)
+            {  /* l'[k] := U[p,k] / a[p,k] */
+               apk->col->ll.ll = temp / apk->val;
+            }
+         }
+skip2:   ;
+      }
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpnpp04.c
===================================================================
--- deps/glpk/src/glpnpp04.c	(revision 9)
+++ deps/glpk/src/glpnpp04.c	(revision 9)
@@ -0,0 +1,1414 @@
+/* glpnpp04.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_binarize_prob - binarize MIP problem
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_binarize_prob(NPP *npp);
+*
+*  DESCRIPTION
+*
+*  The routine npp_binarize_prob replaces in the original MIP problem
+*  every integer variable:
+*
+*     l[q] <= x[q] <= u[q],                                          (1)
+*
+*  where l[q] < u[q], by an equivalent sum of binary variables.
+*
+*  RETURNS
+*
+*  The routine returns the number of integer variables for which the
+*  transformation failed, because u[q] - l[q] > d_max.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  If variable x[q] has non-zero lower bound, it is first processed
+*  with the routine npp_lbnd_col. Thus, we can assume that:
+*
+*     0 <= x[q] <= u[q].                                             (2)
+*
+*  If u[q] = 1, variable x[q] is already binary, so further processing
+*  is not needed. Let, therefore, that 2 <= u[q] <= d_max, and n be a
+*  smallest integer such that u[q] <= 2^n - 1 (n >= 2, since u[q] >= 2).
+*  Then variable x[q] can be replaced by the following sum:
+*
+*            n-1
+*     x[q] = sum 2^k x[k],                                           (3)
+*            k=0
+*
+*  where x[k] are binary columns (variables). If u[q] < 2^n - 1, the
+*  following additional inequality constraint must be also included in
+*  the transformed problem:
+*
+*     n-1
+*     sum 2^k x[k] <= u[q].                                          (4)
+*     k=0
+*
+*  Note: Assuming that in the transformed problem x[q] becomes binary
+*  variable x[0], this transformation causes new n-1 binary variables
+*  to appear.
+*
+*  Substituting x[q] from (3) to the objective row gives:
+*
+*     z = sum c[j] x[j] + c[0] =
+*          j
+*
+*       = sum c[j] x[j] + c[q] x[q] + c[0] =
+*         j!=q
+*                              n-1
+*       = sum c[j] x[j] + c[q] sum 2^k x[k] + c[0] =
+*         j!=q                 k=0
+*                         n-1
+*       = sum c[j] x[j] + sum c[k] x[k] + c[0],
+*         j!=q            k=0
+*
+*  where:
+*
+*     c[k] = 2^k c[q],  k = 0, ..., n-1.                             (5)
+*
+*  And substituting x[q] from (3) to i-th constraint row i gives:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
+*             j!=q
+*                                      n-1
+*     L[i] <= sum a[i,j] x[j] + a[i,q] sum 2^k x[k] <= U[i]  ==>
+*             j!=q                     k=0
+*                               n-1
+*     L[i] <= sum a[i,j] x[j] + sum a[i,k] x[k] <= U[i],
+*             j!=q              k=0
+*
+*  where:
+*
+*     a[i,k] = 2^k a[i,q],  k = 0, ..., n-1.                         (6)
+*
+*  RECOVERING SOLUTION
+*
+*  Value of variable x[q] is computed with formula (3). */
+
+struct binarize
+{     int q;
+      /* column reference number for x[q] = x[0] */
+      int j;
+      /* column reference number for x[1]; x[2] has reference number
+         j+1, x[3] - j+2, etc. */
+      int n;
+      /* total number of binary variables, n >= 2 */
+};
+
+static int rcv_binarize_prob(NPP *npp, void *info);
+
+int npp_binarize_prob(NPP *npp)
+{     /* binarize MIP problem */
+      struct binarize *info;
+      NPPROW *row;
+      NPPCOL *col, *bin;
+      NPPAIJ *aij;
+      int u, n, k, temp, nfails, nvars, nbins, nrows;
+      /* new variables will be added to the end of the column list, so
+         we go from the end to beginning of the column list */
+      nfails = nvars = nbins = nrows = 0;
+      for (col = npp->c_tail; col != NULL; col = col->prev)
+      {  /* skip continuous variable */
+         if (!col->is_int) continue;
+         /* skip fixed variable */
+         if (col->lb == col->ub) continue;
+         /* skip binary variable */
+         if (col->lb == 0.0 && col->ub == 1.0) continue;
+         /* check if the transformation is applicable */
+         if (col->lb < -1e6 || col->ub > +1e6 ||
+             col->ub - col->lb > 4095.0)
+         {  /* unfortunately, not */
+            nfails++;
+            continue;
+         }
+         /* process integer non-binary variable x[q] */
+         nvars++;
+         /* make x[q] non-negative, if its lower bound is non-zero */
+         if (col->lb != 0.0)
+            npp_lbnd_col(npp, col);
+         /* now 0 <= x[q] <= u[q] */
+         xassert(col->lb == 0.0);
+         u = (int)col->ub;
+         xassert(col->ub == (double)u);
+         /* if x[q] is binary, further processing is not needed */
+         if (u == 1) continue;
+         /* determine smallest n such that u <= 2^n - 1 (thus, n is the
+            number of binary variables needed) */
+         n = 2, temp = 4;
+         while (u >= temp)
+            n++, temp += temp;
+         nbins += n;
+         /* create transformation stack entry */
+         info = npp_push_tse(npp,
+            rcv_binarize_prob, sizeof(struct binarize));
+         info->q = col->j;
+         info->j = 0; /* will be set below */
+         info->n = n;
+         /* if u < 2^n - 1, we need one additional row for (4) */
+         if (u < temp - 1)
+         {  row = npp_add_row(npp), nrows++;
+            row->lb = -DBL_MAX, row->ub = u;
+         }
+         else
+            row = NULL;
+         /* in the transformed problem variable x[q] becomes binary
+            variable x[0], so its objective and constraint coefficients
+            are not changed */
+         col->ub = 1.0;
+         /* include x[0] into constraint (4) */
+         if (row != NULL)
+            npp_add_aij(npp, row, col, 1.0);
+         /* add other binary variables x[1], ..., x[n-1] */
+         for (k = 1, temp = 2; k < n; k++, temp += temp)
+         {  /* add new binary variable x[k] */
+            bin = npp_add_col(npp);
+            bin->is_int = 1;
+            bin->lb = 0.0, bin->ub = 1.0;
+            bin->coef = (double)temp * col->coef;
+            /* store column reference number for x[1] */
+            if (info->j == 0)
+               info->j = bin->j;
+            else
+               xassert(info->j + (k-1) == bin->j);
+            /* duplicate constraint coefficients for x[k]; this also
+               automatically includes x[k] into constraint (4) */
+            for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+               npp_add_aij(npp, aij->row, bin, (double)temp * aij->val);
+         }
+      }
+      if (nvars > 0)
+         xprintf("%d integer variable(s) were replaced by %d binary one"
+            "s\n", nvars, nbins);
+      if (nrows > 0)
+         xprintf("%d row(s) were added due to binarization\n", nrows);
+      if (nfails > 0)
+         xprintf("Binarization failed for %d integer variable(s)\n",
+            nfails);
+      return nfails;
+}
+
+static int rcv_binarize_prob(NPP *npp, void *_info)
+{     /* recovery binarized variable */
+      struct binarize *info = _info;
+      int k, temp;
+      double sum;
+      /* compute value of x[q]; see formula (3) */
+      sum = npp->c_value[info->q];
+      for (k = 1, temp = 2; k < info->n; k++, temp += temp)
+         sum += (double)temp * npp->c_value[info->j + (k-1)];
+      npp->c_value[info->q] = sum;
+      return 0;
+}
+
+/**********************************************************************/
+
+struct elem
+{     /* linear form element a[j] x[j] */
+      double aj;
+      /* non-zero coefficient value */
+      NPPCOL *xj;
+      /* pointer to variable (column) */
+      struct elem *next;
+      /* pointer to another term */
+};
+
+static struct elem *copy_form(NPP *npp, NPPROW *row, double s)
+{     /* copy linear form */
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      ptr = NULL;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  e = dmp_get_atom(npp->pool, sizeof(struct elem));
+         e->aj = s * aij->val;
+         e->xj = aij->col;
+         e->next = ptr;
+         ptr = e;
+      }
+      return ptr;
+}
+
+static void drop_form(NPP *npp, struct elem *ptr)
+{     /* drop linear form */
+      struct elem *e;
+      while (ptr != NULL)
+      {  e = ptr;
+         ptr = e->next;
+         dmp_free_atom(npp->pool, e, sizeof(struct elem));
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_is_packing - test if constraint is packing inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_is_packing(NPP *npp, NPPROW *row);
+*
+*  RETURNS
+*
+*  If the specified row (constraint) is packing inequality (see below),
+*  the routine npp_is_packing returns non-zero. Otherwise, it returns
+*  zero.
+*
+*  PACKING INEQUALITIES
+*
+*  In canonical format the packing inequality is the following:
+*
+*     sum  x[j] <= 1,                                                (1)
+*    j in J
+*
+*  where all variables x[j] are binary. This inequality expresses the
+*  condition that in any integer feasible solution at most one variable
+*  from set J can take non-zero (unity) value while other variables
+*  must be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because
+*  if J is empty or |J| = 1, the inequality (1) is redundant.
+*
+*  In general case the packing inequality may include original variables
+*  x[j] as well as their complements x~[j]:
+*
+*     sum   x[j] + sum   x~[j] <= 1,                                 (2)
+*    j in Jp      j in Jn
+*
+*  where Jp and Jn are not intersected. Therefore, using substitution
+*  x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+*     sum   x[j] - sum   x[j] <= 1 - |Jn|.                           (3)
+*    j in Jp      j in Jn */
+
+int npp_is_packing(NPP *npp, NPPROW *row)
+{     /* test if constraint is packing inequality */
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int b;
+      xassert(npp == npp);
+      if (!(row->lb == -DBL_MAX && row->ub != +DBL_MAX))
+         return 0;
+      b = 1;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  col = aij->col;
+         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+            return 0;
+         if (aij->val == +1.0)
+            ;
+         else if (aij->val == -1.0)
+            b--;
+         else
+            return 0;
+      }
+      if (row->ub != (double)b) return 0;
+      return 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_hidden_packing - identify hidden packing inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_hidden_packing(NPP *npp, NPPROW *row);
+*
+*  DESCRIPTION
+*
+*  The routine npp_hidden_packing processes specified inequality
+*  constraint, which includes only binary variables, and the number of
+*  the variables is not less than two. If the original inequality is
+*  equivalent to a packing inequality, the routine replaces it by this
+*  equivalent inequality. If the original constraint is double-sided
+*  inequality, it is replaced by a pair of single-sided inequalities,
+*  if necessary.
+*
+*  RETURNS
+*
+*  If the original inequality constraint was replaced by equivalent
+*  packing inequality, the routine npp_hidden_packing returns non-zero.
+*  Otherwise, it returns zero.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Consider an inequality constraint:
+*
+*     sum  a[j] x[j] <= b,                                           (1)
+*    j in J
+*
+*  where all variables x[j] are binary, and |J| >= 2. (In case of '>='
+*  inequality it can be transformed to '<=' format by multiplying both
+*  its sides by -1.)
+*
+*  Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+*  x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+*     sum   a[j] x[j] <= b  ==>
+*    j in J
+*
+*     sum   a[j] x[j] + sum   a[j] x[j] <= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum   a[j] x[j] + sum   a[j] (1 - x~[j]) <= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum   a[j] x[j] - sum   a[j] x~[j] <= b - sum   a[j].
+*    j in Jp           j in Jn                 j in Jn
+*
+*  Thus, meaning the transformation above, we can assume that in
+*  inequality (1) all coefficients a[j] are positive. Moreover, we can
+*  assume that a[j] <= b. In fact, let a[j] > b; then the following
+*  three cases are possible:
+*
+*  1) b < 0. In this case inequality (1) is infeasible, so the problem
+*     has no feasible solution (see the routine npp_analyze_row);
+*
+*  2) b = 0. In this case inequality (1) is a forcing inequality on its
+*     upper bound (see the routine npp_forcing row), from which it
+*     follows that all variables x[j] should be fixed at zero;
+*
+*  3) b > 0. In this case inequality (1) defines an implied zero upper
+*     bound for variable x[j] (see the routine npp_implied_bounds), from
+*     which it follows that x[j] should be fixed at zero.
+*
+*  It is assumed that all three cases listed above have been recognized
+*  by the routine npp_process_prob, which performs basic MIP processing
+*  prior to a call the routine npp_hidden_packing. So, if one of these
+*  cases occurs, we should just skip processing such constraint.
+*
+*  Thus, let 0 < a[j] <= b. Then it is obvious that constraint (1) is
+*  equivalent to packing inquality only if:
+*
+*     a[j] + a[k] > b + eps                                          (2)
+*
+*  for all j, k in J, j != k, where eps is an absolute tolerance for
+*  row (linear form) value. Checking the condition (2) for all j and k,
+*  j != k, requires time O(|J|^2). However, this time can be reduced to
+*  O(|J|), if use minimal a[j] and a[k], in which case it is sufficient
+*  to check the condition (2) only once.
+*
+*  Once the original inequality (1) is replaced by equivalent packing
+*  inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+*  all j in Jn (see above).
+*
+*  RECOVERING SOLUTION
+*
+*  None needed. */
+
+static int hidden_packing(NPP *npp, struct elem *ptr, double *_b)
+{     /* process inequality constraint: sum a[j] x[j] <= b;
+         0 - specified row is NOT hidden packing inequality;
+         1 - specified row is packing inequality;
+         2 - specified row is hidden packing inequality. */
+      struct elem *e, *ej, *ek;
+      int neg;
+      double b = *_b, eps;
+      xassert(npp == npp);
+      /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+      for (e = ptr; e != NULL; e = e->next)
+      {  xassert(e->aj != 0.0);
+         xassert(e->xj->is_int);
+         xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+      }
+      /* check if the specified inequality constraint already has the
+         form of packing inequality */
+      neg = 0; /* neg is |Jn| */
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj == +1.0)
+            ;
+         else if (e->aj == -1.0)
+            neg++;
+         else
+            break;
+      }
+      if (e == NULL)
+      {  /* all coefficients a[j] are +1 or -1; check rhs b */
+         if (b == (double)(1 - neg))
+         {  /* it is packing inequality; no processing is needed */
+            return 1;
+         }
+      }
+      /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+         positive; the result is a~[j] = |a[j]| and new rhs b */
+      for (e = ptr; e != NULL; e = e->next)
+         if (e->aj < 0) b -= e->aj;
+      /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+      /* if a[j] > b, skip processing--this case must not appear */
+      for (e = ptr; e != NULL; e = e->next)
+         if (fabs(e->aj) > b) return 0;
+      /* now 0 < a[j] <= b for all j in J */
+      /* find two minimal coefficients a[j] and a[k], j != k */
+      ej = NULL;
+      for (e = ptr; e != NULL; e = e->next)
+         if (ej == NULL || fabs(ej->aj) > fabs(e->aj)) ej = e;
+      xassert(ej != NULL);
+      ek = NULL;
+      for (e = ptr; e != NULL; e = e->next)
+         if (e != ej)
+            if (ek == NULL || fabs(ek->aj) > fabs(e->aj)) ek = e;
+      xassert(ek != NULL);
+      /* the specified constraint is equivalent to packing inequality
+         iff a[j] + a[k] > b + eps */
+      eps = 1e-3 + 1e-6 * fabs(b);
+      if (fabs(ej->aj) + fabs(ek->aj) <= b + eps) return 0;
+      /* perform back substitution x~[j] = 1 - x[j] and construct the
+         final equivalent packing inequality in generalized format */
+      b = 1.0;
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj > 0.0)
+            e->aj = +1.0;
+         else /* e->aj < 0.0 */
+            e->aj = -1.0, b -= 1.0;
+      }
+      *_b = b;
+      return 2;
+}
+
+int npp_hidden_packing(NPP *npp, NPPROW *row)
+{     /* identify hidden packing inequality */
+      NPPROW *copy;
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      int kase, ret, count = 0;
+      double b;
+      /* the row must be inequality constraint */
+      xassert(row->lb < row->ub);
+      for (kase = 0; kase <= 1; kase++)
+      {  if (kase == 0)
+         {  /* process row upper bound */
+            if (row->ub == +DBL_MAX) continue;
+            ptr = copy_form(npp, row, +1.0);
+            b = + row->ub;
+         }
+         else
+         {  /* process row lower bound */
+            if (row->lb == -DBL_MAX) continue;
+            ptr = copy_form(npp, row, -1.0);
+            b = - row->lb;
+         }
+         /* now the inequality has the form "sum a[j] x[j] <= b" */
+         ret = hidden_packing(npp, ptr, &b);
+         xassert(0 <= ret && ret <= 2);
+         if (kase == 1 && ret == 1 || ret == 2)
+         {  /* the original inequality has been identified as hidden
+               packing inequality */
+            count++;
+#ifdef GLP_DEBUG
+            xprintf("Original constraint:\n");
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+               xprintf(" %+g x%d", aij->val, aij->col->j);
+            if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+            if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+            xprintf("\n");
+            xprintf("Equivalent packing inequality:\n");
+            for (e = ptr; e != NULL; e = e->next)
+               xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+            xprintf(", <= %g\n", b);
+#endif
+            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+            {  /* the original row is single-sided inequality; no copy
+                  is needed */
+               copy = NULL;
+            }
+            else
+            {  /* the original row is double-sided inequality; we need
+                  to create its copy for other bound before replacing it
+                  with the equivalent inequality */
+               copy = npp_add_row(npp);
+               if (kase == 0)
+               {  /* the copy is for lower bound */
+                  copy->lb = row->lb, copy->ub = +DBL_MAX;
+               }
+               else
+               {  /* the copy is for upper bound */
+                  copy->lb = -DBL_MAX, copy->ub = row->ub;
+               }
+               /* copy original row coefficients */
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  npp_add_aij(npp, copy, aij->col, aij->val);
+            }
+            /* replace the original inequality by equivalent one */
+            npp_erase_row(npp, row);
+            row->lb = -DBL_MAX, row->ub = b;
+            for (e = ptr; e != NULL; e = e->next)
+               npp_add_aij(npp, row, e->xj, e->aj);
+            /* continue processing lower bound for the copy */
+            if (copy != NULL) row = copy;
+         }
+         drop_form(npp, ptr);
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_implied_packing - identify implied packing inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+*     NPPCOL *var[], char set[]);
+*
+*  DESCRIPTION
+*
+*  The routine npp_implied_packing processes specified row (constraint)
+*  of general format:
+*
+*     L <= sum a[j] x[j] <= U.                                       (1)
+*           j
+*
+*  If which = 0, only lower bound L, which must exist, is considered,
+*  while upper bound U is ignored. Similarly, if which = 1, only upper
+*  bound U, which must exist, is considered, while lower bound L is
+*  ignored. Thus, if the specified row is a double-sided inequality or
+*  equality constraint, this routine should be called twice for both
+*  lower and upper bounds.
+*
+*  The routine npp_implied_packing attempts to find a non-trivial (i.e.
+*  having not less than two binary variables) packing inequality:
+*
+*     sum   x[j] - sum   x[j] <= 1 - |Jn|,                           (2)
+*    j in Jp      j in Jn
+*
+*  which is relaxation of the constraint (1) in the sense that any
+*  solution satisfying to that constraint also satisfies to the packing
+*  inequality (2). If such relaxation exists, the routine stores
+*  pointers to descriptors of corresponding binary variables and their
+*  flags, resp., to locations var[1], var[2], ..., var[len] and set[1],
+*  set[2], ..., set[len], where set[j] = 0 means that j in Jp and
+*  set[j] = 1 means that j in Jn.
+*
+*  RETURNS
+*
+*  The routine npp_implied_packing returns len, which is the total
+*  number of binary variables in the packing inequality found, len >= 2.
+*  However, if the relaxation does not exist, the routine returns zero.
+*
+*  ALGORITHM
+*
+*  If which = 0, the constraint coefficients (1) are multiplied by -1
+*  and b is assigned -L; if which = 1, the constraint coefficients (1)
+*  are not changed and b is assigned +U. In both cases the specified
+*  constraint gets the following format:
+*
+*     sum a[j] x[j] <= b.                                            (3)
+*      j
+*
+*  (Note that (3) is a relaxation of (1), because one of bounds L or U
+*  is ignored.)
+*
+*  Let J be set of binary variables, Kp be set of non-binary (integer
+*  or continuous) variables with a[j] > 0, and Kn be set of non-binary
+*  variables with a[j] < 0. Then the inequality (3) can be written as
+*  follows:
+*
+*     sum  a[j] x[j] <= b - sum   a[j] x[j] - sum   a[j] x[j].       (4)
+*    j in J                j in Kp           j in Kn
+*
+*  To get rid of non-binary variables we can replace the inequality (4)
+*  by the following relaxed inequality:
+*
+*     sum  a[j] x[j] <= b~,                                          (5)
+*    j in J
+*
+*  where:
+*
+*     b~ = sup(b - sum   a[j] x[j] - sum   a[j] x[j]) =
+*                 j in Kp           j in Kn
+*
+*        = b - inf sum   a[j] x[j] - inf sum   a[j] x[j] =           (6)
+*                 j in Kp               j in Kn
+*
+*        = b - sum   a[j] l[j] - sum   a[j] u[j].
+*             j in Kp           j in Kn
+*
+*  Note that if lower bound l[j] (if j in Kp) or upper bound u[j]
+*  (if j in Kn) of some non-binary variable x[j] does not exist, then
+*  formally b = +oo, in which case further analysis is not performed.
+*
+*  Let Bp = {j in J: a[j] > 0}, Bn = {j in J: a[j] < 0}. To make all
+*  the inequality coefficients in (5) positive, we replace all x[j] in
+*  Bn by their complementaries, substituting x[j] = 1 - x~[j] for all
+*  j in Bn, that gives:
+*
+*     sum   a[j] x[j] - sum   a[j] x~[j] <= b~ - sum   a[j].         (7)
+*    j in Bp           j in Bn                  j in Bn
+*
+*  This inequality is a relaxation of the original constraint (1), and
+*  it is a binary knapsack inequality. Writing it in the standard format
+*  we have:
+*
+*     sum  alfa[j] z[j] <= beta,                                     (8)
+*    j in J
+*
+*  where:
+*               ( + a[j],   if j in Bp,
+*     alfa[j] = <                                                    (9)
+*               ( - a[j],   if j in Bn,
+*
+*               ( x[j],     if j in Bp,
+*        z[j] = <                                                   (10)
+*               ( 1 - x[j], if j in Bn,
+*
+*        beta = b~ - sum   a[j].                                    (11)
+*                   j in Bn
+*
+*  In the inequality (8) all coefficients are positive, therefore, the
+*  packing relaxation to be found for this inequality is the following:
+*
+*     sum  z[j] <= 1.                                               (12)
+*    j in P
+*
+*  It is obvious that set P within J, which we would like to find, must
+*  satisfy to the following condition:
+*
+*     alfa[j] + alfa[k] > beta + eps  for all j, k in P, j != k,    (13)
+*
+*  where eps is an absolute tolerance for value of the linear form.
+*  Thus, it is natural to take P = {j: alpha[j] > (beta + eps) / 2}.
+*  Moreover, if in the equality (8) there exist coefficients alfa[k],
+*  for which alfa[k] <= (beta + eps) / 2, but which, nevertheless,
+*  satisfies to the condition (13) for all j in P, *one* corresponding
+*  variable z[k] (having, for example, maximal coefficient alfa[k]) can
+*  be included in set P, that allows increasing the number of binary
+*  variables in (12) by one.
+*
+*  Once the set P has been built, for the inequality (12) we need to
+*  perform back substitution according to (10) in order to express it
+*  through the original binary variables. As the result of such back
+*  substitution the relaxed packing inequality get its final format (2),
+*  where Jp = J intersect Bp, and Jn = J intersect Bn. */
+
+int npp_implied_packing(NPP *npp, NPPROW *row, int which,
+      NPPCOL *var[], char set[])
+{     struct elem *ptr, *e, *i, *k;
+      int len = 0;
+      double b, eps;
+      /* build inequality (3) */
+      if (which == 0)
+      {  ptr = copy_form(npp, row, -1.0);
+         xassert(row->lb != -DBL_MAX);
+         b = - row->lb;
+      }
+      else if (which == 1)
+      {  ptr = copy_form(npp, row, +1.0);
+         xassert(row->ub != +DBL_MAX);
+         b = + row->ub;
+      }
+      /* remove non-binary variables to build relaxed inequality (5);
+         compute its right-hand side b~ with formula (6) */
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+         {  /* x[j] is non-binary variable */
+            if (e->aj > 0.0)
+            {  if (e->xj->lb == -DBL_MAX) goto done;
+               b -= e->aj * e->xj->lb;
+            }
+            else /* e->aj < 0.0 */
+            {  if (e->xj->ub == +DBL_MAX) goto done;
+               b -= e->aj * e->xj->ub;
+            }
+            /* a[j] = 0 means that variable x[j] is removed */
+            e->aj = 0.0;
+         }
+      }
+      /* substitute x[j] = 1 - x~[j] to build knapsack inequality (8);
+         compute its right-hand side beta with formula (11) */
+      for (e = ptr; e != NULL; e = e->next)
+         if (e->aj < 0.0) b -= e->aj;
+      /* if beta is close to zero, the knapsack inequality is either
+         infeasible or forcing inequality; this must never happen, so
+         we skip further analysis */
+      if (b < 1e-3) goto done;
+      /* build set P as well as sets Jp and Jn, and determine x[k] as
+         explained above in comments to the routine */
+      eps = 1e-3 + 1e-6 * b;
+      i = k = NULL;
+      for (e = ptr; e != NULL; e = e->next)
+      {  /* note that alfa[j] = |a[j]| */
+         if (fabs(e->aj) > 0.5 * (b + eps))
+         {  /* alfa[j] > (b + eps) / 2; include x[j] in set P, i.e. in
+               set Jp or Jn */
+            var[++len] = e->xj;
+            set[len] = (char)(e->aj > 0.0 ? 0 : 1);
+            /* alfa[i] = min alfa[j] over all j included in set P */
+            if (i == NULL || fabs(i->aj) > fabs(e->aj)) i = e;
+         }
+         else if (fabs(e->aj) >= 1e-3)
+         {  /* alfa[k] = max alfa[j] over all j not included in set P;
+               we skip coefficient a[j] if it is close to zero to avoid
+               numerically unreliable results */
+            if (k == NULL || fabs(k->aj) < fabs(e->aj)) k = e;
+         }
+      }
+      /* if alfa[k] satisfies to condition (13) for all j in P, include
+         x[k] in P */
+      if (i != NULL && k != NULL && fabs(i->aj) + fabs(k->aj) > b + eps)
+      {  var[++len] = k->xj;
+         set[len] = (char)(k->aj > 0.0 ? 0 : 1);
+      }
+      /* trivial packing inequality being redundant must never appear,
+         so we just ignore it */
+      if (len < 2) len = 0;
+done: drop_form(npp, ptr);
+      return len;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_is_covering - test if constraint is covering inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_is_covering(NPP *npp, NPPROW *row);
+*
+*  RETURNS
+*
+*  If the specified row (constraint) is covering inequality (see below),
+*  the routine npp_is_covering returns non-zero. Otherwise, it returns
+*  zero.
+*
+*  COVERING INEQUALITIES
+*
+*  In canonical format the covering inequality is the following:
+*
+*     sum  x[j] >= 1,                                                (1)
+*    j in J
+*
+*  where all variables x[j] are binary. This inequality expresses the
+*  condition that in any integer feasible solution variables in set J
+*  cannot be all equal to zero at the same time, i.e. at least one
+*  variable must take non-zero (unity) value. W.l.o.g. it is assumed
+*  that |J| >= 2, because if J is empty, the inequality (1) is
+*  infeasible, and if |J| = 1, the inequality (1) is a forcing row.
+*
+*  In general case the covering inequality may include original
+*  variables x[j] as well as their complements x~[j]:
+*
+*     sum   x[j] + sum   x~[j] >= 1,                                 (2)
+*    j in Jp      j in Jn
+*
+*  where Jp and Jn are not intersected. Therefore, using substitution
+*  x~[j] = 1 - x[j] gives the packing inequality in generalized format:
+*
+*     sum   x[j] - sum   x[j] >= 1 - |Jn|.                           (3)
+*    j in Jp      j in Jn
+*
+*  (May note that the inequality (3) cuts off infeasible solutions,
+*  where x[j] = 0 for all j in Jp and x[j] = 1 for all j in Jn.)
+*
+*  NOTE: If |J| = 2, the inequality (3) is equivalent to packing
+*        inequality (see the routine npp_is_packing). */
+
+int npp_is_covering(NPP *npp, NPPROW *row)
+{     /* test if constraint is covering inequality */
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int b;
+      xassert(npp == npp);
+      if (!(row->lb != -DBL_MAX && row->ub == +DBL_MAX))
+         return 0;
+      b = 1;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  col = aij->col;
+         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+            return 0;
+         if (aij->val == +1.0)
+            ;
+         else if (aij->val == -1.0)
+            b--;
+         else
+            return 0;
+      }
+      if (row->lb != (double)b) return 0;
+      return 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_hidden_covering - identify hidden covering inequality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_hidden_covering(NPP *npp, NPPROW *row);
+*
+*  DESCRIPTION
+*
+*  The routine npp_hidden_covering processes specified inequality
+*  constraint, which includes only binary variables, and the number of
+*  the variables is not less than three. If the original inequality is
+*  equivalent to a covering inequality (see below), the routine
+*  replaces it by the equivalent inequality. If the original constraint
+*  is double-sided inequality, it is replaced by a pair of single-sided
+*  inequalities, if necessary.
+*
+*  RETURNS
+*
+*  If the original inequality constraint was replaced by equivalent
+*  covering inequality, the routine npp_hidden_covering returns
+*  non-zero. Otherwise, it returns zero.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  Consider an inequality constraint:
+*
+*     sum  a[j] x[j] >= b,                                           (1)
+*    j in J
+*
+*  where all variables x[j] are binary, and |J| >= 3. (In case of '<='
+*  inequality it can be transformed to '>=' format by multiplying both
+*  its sides by -1.)
+*
+*  Let Jp = {j: a[j] > 0}, Jn = {j: a[j] < 0}. Performing substitution
+*  x[j] = 1 - x~[j] for all j in Jn, we have:
+*
+*     sum   a[j] x[j] >= b  ==>
+*    j in J
+*
+*     sum   a[j] x[j] + sum   a[j] x[j] >= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum   a[j] x[j] + sum   a[j] (1 - x~[j]) >= b  ==>
+*    j in Jp           j in Jn
+*
+*     sum  m   a[j] x[j] - sum   a[j] x~[j] >= b - sum   a[j].
+*    j in Jp              j in Jn                 j in Jn
+*
+*  Thus, meaning the transformation above, we can assume that in
+*  inequality (1) all coefficients a[j] are positive. Moreover, we can
+*  assume that b > 0, because otherwise the inequality (1) would be
+*  redundant (see the routine npp_analyze_row). It is then obvious that
+*  constraint (1) is equivalent to covering inequality only if:
+*
+*     a[j] >= b,                                                     (2)
+*
+*  for all j in J.
+*
+*  Once the original inequality (1) is replaced by equivalent covering
+*  inequality, we need to perform back substitution x~[j] = 1 - x[j] for
+*  all j in Jn (see above).
+*
+*  RECOVERING SOLUTION
+*
+*  None needed. */
+
+static int hidden_covering(NPP *npp, struct elem *ptr, double *_b)
+{     /* process inequality constraint: sum a[j] x[j] >= b;
+         0 - specified row is NOT hidden covering inequality;
+         1 - specified row is covering inequality;
+         2 - specified row is hidden covering inequality. */
+      struct elem *e;
+      int neg;
+      double b = *_b, eps;
+      xassert(npp == npp);
+      /* a[j] must be non-zero, x[j] must be binary, for all j in J */
+      for (e = ptr; e != NULL; e = e->next)
+      {  xassert(e->aj != 0.0);
+         xassert(e->xj->is_int);
+         xassert(e->xj->lb == 0.0 && e->xj->ub == 1.0);
+      }
+      /* check if the specified inequality constraint already has the
+         form of covering inequality */
+      neg = 0; /* neg is |Jn| */
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj == +1.0)
+            ;
+         else if (e->aj == -1.0)
+            neg++;
+         else
+            break;
+      }
+      if (e == NULL)
+      {  /* all coefficients a[j] are +1 or -1; check rhs b */
+         if (b == (double)(1 - neg))
+         {  /* it is covering inequality; no processing is needed */
+            return 1;
+         }
+      }
+      /* substitute x[j] = 1 - x~[j] for all j in Jn to make all a[j]
+         positive; the result is a~[j] = |a[j]| and new rhs b */
+      for (e = ptr; e != NULL; e = e->next)
+         if (e->aj < 0) b -= e->aj;
+      /* now a[j] > 0 for all j in J (actually |a[j]| are used) */
+      /* if b <= 0, skip processing--this case must not appear */
+      if (b < 1e-3) return 0;
+      /* now a[j] > 0 for all j in J, and b > 0 */
+      /* the specified constraint is equivalent to covering inequality
+         iff a[j] >= b for all j in J */
+      eps = 1e-9 + 1e-12 * fabs(b);
+      for (e = ptr; e != NULL; e = e->next)
+         if (fabs(e->aj) < b - eps) return 0;
+      /* perform back substitution x~[j] = 1 - x[j] and construct the
+         final equivalent covering inequality in generalized format */
+      b = 1.0;
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj > 0.0)
+            e->aj = +1.0;
+         else /* e->aj < 0.0 */
+            e->aj = -1.0, b -= 1.0;
+      }
+      *_b = b;
+      return 2;
+}
+
+int npp_hidden_covering(NPP *npp, NPPROW *row)
+{     /* identify hidden covering inequality */
+      NPPROW *copy;
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      int kase, ret, count = 0;
+      double b;
+      /* the row must be inequality constraint */
+      xassert(row->lb < row->ub);
+      for (kase = 0; kase <= 1; kase++)
+      {  if (kase == 0)
+         {  /* process row lower bound */
+            if (row->lb == -DBL_MAX) continue;
+            ptr = copy_form(npp, row, +1.0);
+            b = + row->lb;
+         }
+         else
+         {  /* process row upper bound */
+            if (row->ub == +DBL_MAX) continue;
+            ptr = copy_form(npp, row, -1.0);
+            b = - row->ub;
+         }
+         /* now the inequality has the form "sum a[j] x[j] >= b" */
+         ret = hidden_covering(npp, ptr, &b);
+         xassert(0 <= ret && ret <= 2);
+         if (kase == 1 && ret == 1 || ret == 2)
+         {  /* the original inequality has been identified as hidden
+               covering inequality */
+            count++;
+#ifdef GLP_DEBUG
+            xprintf("Original constraint:\n");
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+               xprintf(" %+g x%d", aij->val, aij->col->j);
+            if (row->lb != -DBL_MAX) xprintf(", >= %g", row->lb);
+            if (row->ub != +DBL_MAX) xprintf(", <= %g", row->ub);
+            xprintf("\n");
+            xprintf("Equivalent covering inequality:\n");
+            for (e = ptr; e != NULL; e = e->next)
+               xprintf(" %sx%d", e->aj > 0.0 ? "+" : "-", e->xj->j);
+            xprintf(", >= %g\n", b);
+#endif
+            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+            {  /* the original row is single-sided inequality; no copy
+                  is needed */
+               copy = NULL;
+            }
+            else
+            {  /* the original row is double-sided inequality; we need
+                  to create its copy for other bound before replacing it
+                  with the equivalent inequality */
+               copy = npp_add_row(npp);
+               if (kase == 0)
+               {  /* the copy is for upper bound */
+                  copy->lb = -DBL_MAX, copy->ub = row->ub;
+               }
+               else
+               {  /* the copy is for lower bound */
+                  copy->lb = row->lb, copy->ub = +DBL_MAX;
+               }
+               /* copy original row coefficients */
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  npp_add_aij(npp, copy, aij->col, aij->val);
+            }
+            /* replace the original inequality by equivalent one */
+            npp_erase_row(npp, row);
+            row->lb = b, row->ub = +DBL_MAX;
+            for (e = ptr; e != NULL; e = e->next)
+               npp_add_aij(npp, row, e->xj, e->aj);
+            /* continue processing upper bound for the copy */
+            if (copy != NULL) row = copy;
+         }
+         drop_form(npp, ptr);
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_is_partitioning - test if constraint is partitioning equality
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_is_partitioning(NPP *npp, NPPROW *row);
+*
+*  RETURNS
+*
+*  If the specified row (constraint) is partitioning equality (see
+*  below), the routine npp_is_partitioning returns non-zero. Otherwise,
+*  it returns zero.
+*
+*  PARTITIONING EQUALITIES
+*
+*  In canonical format the partitioning equality is the following:
+*
+*     sum  x[j] = 1,                                                 (1)
+*    j in J
+*
+*  where all variables x[j] are binary. This equality expresses the
+*  condition that in any integer feasible solution exactly one variable
+*  in set J must take non-zero (unity) value while other variables must
+*  be equal to zero. W.l.o.g. it is assumed that |J| >= 2, because if
+*  J is empty, the inequality (1) is infeasible, and if |J| = 1, the
+*  inequality (1) is a fixing row.
+*
+*  In general case the partitioning equality may include original
+*  variables x[j] as well as their complements x~[j]:
+*
+*     sum   x[j] + sum   x~[j] = 1,                                  (2)
+*    j in Jp      j in Jn
+*
+*  where Jp and Jn are not intersected. Therefore, using substitution
+*  x~[j] = 1 - x[j] leads to the partitioning equality in generalized
+*  format:
+*
+*     sum   x[j] - sum   x[j] = 1 - |Jn|.                            (3)
+*    j in Jp      j in Jn */
+
+int npp_is_partitioning(NPP *npp, NPPROW *row)
+{     /* test if constraint is partitioning equality */
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int b;
+      xassert(npp == npp);
+      if (row->lb != row->ub) return 0;
+      b = 1;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  col = aij->col;
+         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+            return 0;
+         if (aij->val == +1.0)
+            ;
+         else if (aij->val == -1.0)
+            b--;
+         else
+            return 0;
+      }
+      if (row->lb != (double)b) return 0;
+      return 1;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_reduce_ineq_coef - reduce inequality constraint coefficients
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_reduce_ineq_coef(NPP *npp, NPPROW *row);
+*
+*  DESCRIPTION
+*
+*  The routine npp_reduce_ineq_coef processes specified inequality
+*  constraint attempting to replace it by an equivalent constraint,
+*  where magnitude of coefficients at binary variables is smaller than
+*  in the original constraint. If the inequality is double-sided, it is
+*  replaced by a pair of single-sided inequalities, if necessary.
+*
+*  RETURNS
+*
+*  The routine npp_reduce_ineq_coef returns the number of coefficients
+*  reduced.
+*
+*  BACKGROUND
+*
+*  Consider an inequality constraint:
+*
+*     sum  a[j] x[j] >= b.                                           (1)
+*    j in J
+*
+*  (In case of '<=' inequality it can be transformed to '>=' format by
+*  multiplying both its sides by -1.) Let x[k] be a binary variable;
+*  other variables can be integer as well as continuous. We can write
+*  constraint (1) as follows:
+*
+*     a[k] x[k] + t[k] >= b,                                         (2)
+*
+*  where:
+*
+*     t[k] = sum      a[j] x[j].                                     (3)
+*           j in J\{k}
+*
+*  Since x[k] is binary, constraint (2) is equivalent to disjunction of
+*  the following two constraints:
+*
+*     x[k] = 0,  t[k] >= b                                           (4)
+*
+*        OR
+*
+*     x[k] = 1,  t[k] >= b - a[k].                                   (5)
+*
+*  Let also that for the partial sum t[k] be known some its implied
+*  lower bound inf t[k].
+*
+*  Case a[k] > 0. Let inf t[k] < b, since otherwise both constraints
+*  (4) and (5) and therefore constraint (2) are redundant.
+*  If inf t[k] > b - a[k], only constraint (5) is redundant, in which
+*  case it can be replaced with the following redundant and therefore
+*  equivalent constraint:
+*
+*     t[k] >= b - a'[k] = inf t[k],                                  (6)
+*
+*  where:
+*
+*     a'[k] = b - inf t[k].                                          (7)
+*
+*  Thus, the original constraint (2) is equivalent to the following
+*  constraint with coefficient at variable x[k] changed:
+*
+*     a'[k] x[k] + t[k] >= b.                                        (8)
+*
+*  From inf t[k] < b it follows that a'[k] > 0, i.e. the coefficient
+*  at x[k] keeps its sign. And from inf t[k] > b - a[k] it follows that
+*  a'[k] < a[k], i.e. the coefficient reduces in magnitude.
+*
+*  Case a[k] < 0. Let inf t[k] < b - a[k], since otherwise both
+*  constraints (4) and (5) and therefore constraint (2) are redundant.
+*  If inf t[k] > b, only constraint (4) is redundant, in which case it
+*  can be replaced with the following redundant and therefore equivalent
+*  constraint:
+*
+*     t[k] >= b' = inf t[k].                                         (9)
+*
+*  Rewriting constraint (5) as follows:
+*
+*     t[k] >= b - a[k] = b' - a'[k],                                (10)
+*
+*  where:
+*
+*     a'[k] = a[k] + b' - b = a[k] + inf t[k] - b,                  (11)
+*
+*  we can see that disjunction of constraint (9) and (10) is equivalent
+*  to disjunction of constraint (4) and (5), from which it follows that
+*  the original constraint (2) is equivalent to the following constraint
+*  with both coefficient at variable x[k] and right-hand side changed:
+*
+*     a'[k] x[k] + t[k] >= b'.                                      (12)
+*
+*  From inf t[k] < b - a[k] it follows that a'[k] < 0, i.e. the
+*  coefficient at x[k] keeps its sign. And from inf t[k] > b it follows
+*  that a'[k] > a[k], i.e. the coefficient reduces in magnitude.
+*
+*  PROBLEM TRANSFORMATION
+*
+*  In the routine npp_reduce_ineq_coef the following implied lower
+*  bound of the partial sum (3) is used:
+*
+*     inf t[k] = sum       a[j] l[j] + sum       a[j] u[j],         (13)
+*               j in Jp\{k}           k in Jn\{k}
+*
+*  where Jp = {j : a[j] > 0}, Jn = {j : a[j] < 0}, l[j] and u[j] are
+*  lower and upper bounds, resp., of variable x[j].
+*
+*  In order to compute inf t[k] more efficiently, the following formula,
+*  which is equivalent to (13), is actually used:
+*
+*                ( h - a[k] l[k] = h,        if a[k] > 0,
+*     inf t[k] = <                                                  (14)
+*                ( h - a[k] u[k] = h - a[k], if a[k] < 0,
+*
+*  where:
+*
+*     h = sum   a[j] l[j] + sum   a[j] u[j]                         (15)
+*        j in Jp           j in Jn
+*
+*  is the implied lower bound of row (1).
+*
+*  Reduction of positive coefficient (a[k] > 0) does not change value
+*  of h, since l[k] = 0. In case of reduction of negative coefficient
+*  (a[k] < 0) from (11) it follows that:
+*
+*     delta a[k] = a'[k] - a[k] = inf t[k] - b  (> 0),              (16)
+*
+*  so new value of h (accounting that u[k] = 1) can be computed as
+*  follows:
+*
+*     h := h + delta a[k] = h + (inf t[k] - b).                     (17)
+*
+*  RECOVERING SOLUTION
+*
+*  None needed. */
+
+static int reduce_ineq_coef(NPP *npp, struct elem *ptr, double *_b)
+{     /* process inequality constraint: sum a[j] x[j] >= b */
+      /* returns: the number of coefficients reduced */
+      struct elem *e;
+      int count = 0;
+      double h, inf_t, new_a, b = *_b;
+      xassert(npp == npp);
+      /* compute h; see (15) */
+      h = 0.0;
+      for (e = ptr; e != NULL; e = e->next)
+      {  if (e->aj > 0.0)
+         {  if (e->xj->lb == -DBL_MAX) goto done;
+            h += e->aj * e->xj->lb;
+         }
+         else /* e->aj < 0.0 */
+         {  if (e->xj->ub == +DBL_MAX) goto done;
+            h += e->aj * e->xj->ub;
+         }
+      }
+      /* perform reduction of coefficients at binary variables */
+      for (e = ptr; e != NULL; e = e->next)
+      {  /* skip non-binary variable */
+         if (!(e->xj->is_int && e->xj->lb == 0.0 && e->xj->ub == 1.0))
+            continue;
+         if (e->aj > 0.0)
+         {  /* compute inf t[k]; see (14) */
+            inf_t = h;
+            if (b - e->aj < inf_t && inf_t < b)
+            {  /* compute reduced coefficient a'[k]; see (7) */
+               new_a = b - inf_t;
+               if (new_a >= +1e-3 &&
+                   e->aj - new_a >= 0.01 * (1.0 + e->aj))
+               {  /* accept a'[k] */
+#ifdef GLP_DEBUG
+                  xprintf("+");
+#endif
+                  e->aj = new_a;
+                  count++;
+               }
+            }
+         }
+         else /* e->aj < 0.0 */
+         {  /* compute inf t[k]; see (14) */
+            inf_t = h - e->aj;
+            if (b < inf_t && inf_t < b - e->aj)
+            {  /* compute reduced coefficient a'[k]; see (11) */
+               new_a = e->aj + (inf_t - b);
+               if (new_a <= -1e-3 &&
+                   new_a - e->aj >= 0.01 * (1.0 - e->aj))
+               {  /* accept a'[k] */
+#ifdef GLP_DEBUG
+                  xprintf("-");
+#endif
+                  e->aj = new_a;
+                  /* update h; see (17) */
+                  h += (inf_t - b);
+                  /* compute b'; see (9) */
+                  b = inf_t;
+                  count++;
+               }
+            }
+         }
+      }
+      *_b = b;
+done: return count;
+}
+
+int npp_reduce_ineq_coef(NPP *npp, NPPROW *row)
+{     /* reduce inequality constraint coefficients */
+      NPPROW *copy;
+      NPPAIJ *aij;
+      struct elem *ptr, *e;
+      int kase, count[2];
+      double b;
+      /* the row must be inequality constraint */
+      xassert(row->lb < row->ub);
+      count[0] = count[1] = 0;
+      for (kase = 0; kase <= 1; kase++)
+      {  if (kase == 0)
+         {  /* process row lower bound */
+            if (row->lb == -DBL_MAX) continue;
+#ifdef GLP_DEBUG
+            xprintf("L");
+#endif
+            ptr = copy_form(npp, row, +1.0);
+            b = + row->lb;
+         }
+         else
+         {  /* process row upper bound */
+            if (row->ub == +DBL_MAX) continue;
+#ifdef GLP_DEBUG
+            xprintf("U");
+#endif
+            ptr = copy_form(npp, row, -1.0);
+            b = - row->ub;
+         }
+         /* now the inequality has the form "sum a[j] x[j] >= b" */
+         count[kase] = reduce_ineq_coef(npp, ptr, &b);
+         if (count[kase] > 0)
+         {  /* the original inequality has been replaced by equivalent
+               one with coefficients reduced */
+            if (row->lb == -DBL_MAX || row->ub == +DBL_MAX)
+            {  /* the original row is single-sided inequality; no copy
+                  is needed */
+               copy = NULL;
+            }
+            else
+            {  /* the original row is double-sided inequality; we need
+                  to create its copy for other bound before replacing it
+                  with the equivalent inequality */
+#ifdef GLP_DEBUG
+               xprintf("*");
+#endif
+               copy = npp_add_row(npp);
+               if (kase == 0)
+               {  /* the copy is for upper bound */
+                  copy->lb = -DBL_MAX, copy->ub = row->ub;
+               }
+               else
+               {  /* the copy is for lower bound */
+                  copy->lb = row->lb, copy->ub = +DBL_MAX;
+               }
+               /* copy original row coefficients */
+               for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                  npp_add_aij(npp, copy, aij->col, aij->val);
+            }
+            /* replace the original inequality by equivalent one */
+            npp_erase_row(npp, row);
+            row->lb = b, row->ub = +DBL_MAX;
+            for (e = ptr; e != NULL; e = e->next)
+               npp_add_aij(npp, row, e->xj, e->aj);
+            /* continue processing upper bound for the copy */
+            if (copy != NULL) row = copy;
+         }
+         drop_form(npp, ptr);
+      }
+      return count[0] + count[1];
+}
+
+/* eof */
Index: deps/glpk/src/glpnpp05.c
===================================================================
--- deps/glpk/src/glpnpp05.c	(revision 9)
+++ deps/glpk/src/glpnpp05.c	(revision 9)
@@ -0,0 +1,809 @@
+/* glpnpp05.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  NAME
+*
+*  npp_clean_prob - perform initial LP/MIP processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  void npp_clean_prob(NPP *npp);
+*
+*  DESCRIPTION
+*
+*  The routine npp_clean_prob performs initial LP/MIP processing that
+*  currently includes:
+*
+*  1) removing free rows;
+*
+*  2) replacing double-sided constraint rows with almost identical
+*     bounds, by equality constraint rows;
+*
+*  3) removing fixed columns;
+*
+*  4) replacing double-bounded columns with almost identical bounds by
+*     fixed columns and removing those columns;
+*
+*  5) initial processing constraint coefficients (not implemented);
+*
+*  6) initial processing objective coefficients (not implemented). */
+
+void npp_clean_prob(NPP *npp)
+{     /* perform initial LP/MIP processing */
+      NPPROW *row, *next_row;
+      NPPCOL *col, *next_col;
+      int ret;
+      xassert(npp == npp);
+      /* process rows which originally are free */
+      for (row = npp->r_head; row != NULL; row = next_row)
+      {  next_row = row->next;
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+         {  /* process free row */
+#ifdef GLP_DEBUG
+            xprintf("1");
+#endif
+            npp_free_row(npp, row);
+            /* row was deleted */
+         }
+      }
+      /* process rows which originally are double-sided inequalities */
+      for (row = npp->r_head; row != NULL; row = next_row)
+      {  next_row = row->next;
+         if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
+             row->lb < row->ub)
+         {  ret = npp_make_equality(npp, row);
+            if (ret == 0)
+               ;
+            else if (ret == 1)
+            {  /* row was replaced by equality constraint */
+#ifdef GLP_DEBUG
+               xprintf("2");
+#endif
+            }
+            else
+               xassert(ret != ret);
+         }
+      }
+      /* process columns which are originally fixed */
+      for (col = npp->c_head; col != NULL; col = next_col)
+      {  next_col = col->next;
+         if (col->lb == col->ub)
+         {  /* process fixed column */
+#ifdef GLP_DEBUG
+            xprintf("3");
+#endif
+            npp_fixed_col(npp, col);
+            /* column was deleted */
+         }
+      }
+      /* process columns which are originally double-bounded */
+      for (col = npp->c_head; col != NULL; col = next_col)
+      {  next_col = col->next;
+         if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
+             col->lb < col->ub)
+         {  ret = npp_make_fixed(npp, col);
+            if (ret == 0)
+               ;
+            else if (ret == 1)
+            {  /* column was replaced by fixed column; process it */
+#ifdef GLP_DEBUG
+               xprintf("4");
+#endif
+               npp_fixed_col(npp, col);
+               /* column was deleted */
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_process_row - perform basic row processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_process_row(NPP *npp, NPPROW *row, int hard);
+*
+*  DESCRIPTION
+*
+*  The routine npp_process_row performs basic row processing that
+*  currently includes:
+*
+*  1) removing empty row;
+*
+*  2) removing equality constraint row singleton and corresponding
+*     column;
+*
+*  3) removing inequality constraint row singleton and corresponding
+*     column if it was fixed;
+*
+*  4) performing general row analysis;
+*
+*  5) removing redundant row bounds;
+*
+*  6) removing forcing row and corresponding columns;
+*
+*  7) removing row which becomes free due to redundant bounds;
+*
+*  8) computing implied bounds for all columns in the row and using
+*     them to strengthen current column bounds (MIP only, optional,
+*     performed if the flag hard is on).
+*
+*  Additionally the routine may activate affected rows and/or columns
+*  for further processing.
+*
+*  RETURNS
+*
+*  0           success;
+*
+*  GLP_ENOPFS  primal/integer infeasibility detected;
+*
+*  GLP_ENODFS  dual infeasibility detected. */
+
+int npp_process_row(NPP *npp, NPPROW *row, int hard)
+{     /* perform basic row processing */
+      NPPCOL *col;
+      NPPAIJ *aij, *next_aij, *aaa;
+      int ret;
+      /* row must not be free */
+      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+      /* start processing row */
+      if (row->ptr == NULL)
+      {  /* empty row */
+         ret = npp_empty_row(npp, row);
+         if (ret == 0)
+         {  /* row was deleted */
+#ifdef GLP_DEBUG
+            xprintf("A");
+#endif
+            return 0;
+         }
+         else if (ret == 1)
+         {  /* primal infeasibility */
+            return GLP_ENOPFS;
+         }
+         else
+            xassert(ret != ret);
+      }
+      if (row->ptr->r_next == NULL)
+      {  /* row singleton */
+         col = row->ptr->col;
+         if (row->lb == row->ub)
+         {  /* equality constraint */
+            ret = npp_eq_singlet(npp, row);
+            if (ret == 0)
+            {  /* column was fixed, row was deleted */
+#ifdef GLP_DEBUG
+               xprintf("B");
+#endif
+               /* activate rows affected by column */
+               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                  npp_activate_row(npp, aij->row);
+               /* process fixed column */
+               npp_fixed_col(npp, col);
+               /* column was deleted */
+               return 0;
+            }
+            else if (ret == 1 || ret == 2)
+            {  /* primal/integer infeasibility */
+               return GLP_ENOPFS;
+            }
+            else
+               xassert(ret != ret);
+         }
+         else
+         {  /* inequality constraint */
+            ret = npp_ineq_singlet(npp, row);
+            if (0 <= ret && ret <= 3)
+            {  /* row was deleted */
+#ifdef GLP_DEBUG
+               xprintf("C");
+#endif
+               /* activate column, since its length was changed due to
+                  row deletion */
+               npp_activate_col(npp, col);
+               if (ret >= 2)
+               {  /* column bounds changed significantly or column was
+                     fixed */
+                  /* activate rows affected by column */
+                  for (aij = col->ptr; aij != NULL; aij = aij->c_next)
+                     npp_activate_row(npp, aij->row);
+               }
+               if (ret == 3)
+               {  /* column was fixed; process it */
+#ifdef GLP_DEBUG
+                  xprintf("D");
+#endif
+                  npp_fixed_col(npp, col);
+                  /* column was deleted */
+               }
+               return 0;
+            }
+            else if (ret == 4)
+            {  /* primal infeasibility */
+               return GLP_ENOPFS;
+            }
+            else
+               xassert(ret != ret);
+         }
+      }
+#if 0
+      /* sometimes this causes too large round-off errors; probably
+         pivot coefficient should be chosen more carefully */
+      if (row->ptr->r_next->r_next == NULL)
+      {  /* row doubleton */
+         if (row->lb == row->ub)
+         {  /* equality constraint */
+            if (!(row->ptr->col->is_int ||
+                  row->ptr->r_next->col->is_int))
+            {  /* both columns are continuous */
+               NPPCOL *q;
+               q = npp_eq_doublet(npp, row);
+               if (q != NULL)
+               {  /* column q was eliminated */
+#ifdef GLP_DEBUG
+                  xprintf("E");
+#endif
+                  /* now column q is singleton of type "implied slack
+                     variable"; we process it here to make sure that on
+                     recovering basic solution the row is always active
+                     equality constraint (as required by the routine
+                     rcv_eq_doublet) */
+                  xassert(npp_process_col(npp, q) == 0);
+                  /* column q was deleted; note that row p also may be
+                     deleted */
+                  return 0;
+               }
+            }
+         }
+      }
+#endif
+      /* general row analysis */
+      ret = npp_analyze_row(npp, row);
+      xassert(0x00 <= ret && ret <= 0xFF);
+      if (ret == 0x33)
+      {  /* row bounds are inconsistent with column bounds */
+         return GLP_ENOPFS;
+      }
+      if ((ret & 0x0F) == 0x00)
+      {  /* row lower bound does not exist or redundant */
+         if (row->lb != -DBL_MAX)
+         {  /* remove redundant row lower bound */
+#ifdef GLP_DEBUG
+            xprintf("F");
+#endif
+            npp_inactive_bound(npp, row, 0);
+         }
+      }
+      else if ((ret & 0x0F) == 0x01)
+      {  /* row lower bound can be active */
+         /* see below */
+      }
+      else if ((ret & 0x0F) == 0x02)
+      {  /* row lower bound is a forcing bound */
+#ifdef GLP_DEBUG
+         xprintf("G");
+#endif
+         /* process forcing row */
+         if (npp_forcing_row(npp, row, 0) == 0)
+fixup:   {  /* columns were fixed, row was made free */
+            for (aij = row->ptr; aij != NULL; aij = next_aij)
+            {  /* process column fixed by forcing row */
+#ifdef GLP_DEBUG
+               xprintf("H");
+#endif
+               col = aij->col;
+               next_aij = aij->r_next;
+               /* activate rows affected by column */
+               for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+                  npp_activate_row(npp, aaa->row);
+               /* process fixed column */
+               npp_fixed_col(npp, col);
+               /* column was deleted */
+            }
+            /* process free row (which now is empty due to deletion of
+               all its columns) */
+            npp_free_row(npp, row);
+            /* row was deleted */
+            return 0;
+         }
+      }
+      else
+         xassert(ret != ret);
+      if ((ret & 0xF0) == 0x00)
+      {  /* row upper bound does not exist or redundant */
+         if (row->ub != +DBL_MAX)
+         {  /* remove redundant row upper bound */
+#ifdef GLP_DEBUG
+            xprintf("I");
+#endif
+            npp_inactive_bound(npp, row, 1);
+         }
+      }
+      else if ((ret & 0xF0) == 0x10)
+      {  /* row upper bound can be active */
+         /* see below */
+      }
+      else if ((ret & 0xF0) == 0x20)
+      {  /* row upper bound is a forcing bound */
+#ifdef GLP_DEBUG
+         xprintf("J");
+#endif
+         /* process forcing row */
+         if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
+      }
+      else
+         xassert(ret != ret);
+      if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+      {  /* row became free due to redundant bounds removal */
+#ifdef GLP_DEBUG
+         xprintf("K");
+#endif
+         /* activate its columns, since their length will change due
+            to row deletion */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+            npp_activate_col(npp, aij->col);
+         /* process free row */
+         npp_free_row(npp, row);
+         /* row was deleted */
+         return 0;
+      }
+#if 1 /* 23/XII-2009 */
+      /* row lower and/or upper bounds can be active */
+      if (npp->sol == GLP_MIP && hard)
+      {  /* improve current column bounds (optional) */
+         if (npp_improve_bounds(npp, row, 1) < 0)
+            return GLP_ENOPFS;
+      }
+#endif
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_improve_bounds - improve current column bounds
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
+*
+*  DESCRIPTION
+*
+*  The routine npp_improve_bounds analyzes specified row (inequality
+*  or equality constraint) to determine implied column bounds and then
+*  uses these bounds to improve (strengthen) current column bounds.
+*
+*  If the flag is on and current column bounds changed significantly
+*  or the column was fixed, the routine activate rows affected by the
+*  column for further processing. (This feature is intended to be used
+*  in the main loop of the routine npp_process_row.)
+*
+*  NOTE: This operation can be used for MIP problem only.
+*
+*  RETURNS
+*
+*  The routine npp_improve_bounds returns the number of significantly
+*  changed bounds plus the number of column having been fixed due to
+*  bound improvements. However, if the routine detects primal/integer
+*  infeasibility, it returns a negative value. */
+
+int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
+{     /* improve current column bounds */
+      NPPCOL *col;
+      NPPAIJ *aij, *next_aij, *aaa;
+      int kase, ret, count = 0;
+      double lb, ub;
+      xassert(npp->sol == GLP_MIP);
+      /* row must not be free */
+      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+      /* determine implied column bounds */
+      npp_implied_bounds(npp, row);
+      /* and use these bounds to strengthen current column bounds */
+      for (aij = row->ptr; aij != NULL; aij = next_aij)
+      {  col = aij->col;
+         next_aij = aij->r_next;
+         for (kase = 0; kase <= 1; kase++)
+         {  /* save current column bounds */
+            lb = col->lb, ub = col->ub;
+            if (kase == 0)
+            {  /* process implied column lower bound */
+               if (col->ll.ll == -DBL_MAX) continue;
+               ret = npp_implied_lower(npp, col, col->ll.ll);
+            }
+            else
+            {  /* process implied column upper bound */
+               if (col->uu.uu == +DBL_MAX) continue;
+               ret = npp_implied_upper(npp, col, col->uu.uu);
+            }
+            if (ret == 0 || ret == 1)
+            {  /* current column bounds did not change or changed, but
+                  not significantly; restore current column bounds */
+               col->lb = lb, col->ub = ub;
+            }
+            else if (ret == 2 || ret == 3)
+            {  /* current column bounds changed significantly or column
+                  was fixed */
+#ifdef GLP_DEBUG
+               xprintf("L");
+#endif
+               count++;
+               /* activate other rows affected by column, if required */
+               if (flag)
+               {  for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
+                  {  if (aaa->row != row)
+                        npp_activate_row(npp, aaa->row);
+                  }
+               }
+               if (ret == 3)
+               {  /* process fixed column */
+#ifdef GLP_DEBUG
+                  xprintf("M");
+#endif
+                  npp_fixed_col(npp, col);
+                  /* column was deleted */
+                  break; /* for kase */
+               }
+            }
+            else if (ret == 4)
+            {  /* primal/integer infeasibility */
+               return -1;
+            }
+            else
+               xassert(ret != ret);
+         }
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_process_col - perform basic column processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_process_col(NPP *npp, NPPCOL *col);
+*
+*  DESCRIPTION
+*
+*  The routine npp_process_col performs basic column processing that
+*  currently includes:
+*
+*  1) fixing and removing empty column;
+*
+*  2) removing column singleton, which is implied slack variable, and
+*     corresponding row if it becomes free;
+*
+*  3) removing bounds of column, which is implied free variable, and
+*     replacing corresponding row by equality constraint.
+*
+*  Additionally the routine may activate affected rows and/or columns
+*  for further processing.
+*
+*  RETURNS
+*
+*  0           success;
+*
+*  GLP_ENOPFS  primal/integer infeasibility detected;
+*
+*  GLP_ENODFS  dual infeasibility detected. */
+
+int npp_process_col(NPP *npp, NPPCOL *col)
+{     /* perform basic column processing */
+      NPPROW *row;
+      NPPAIJ *aij;
+      int ret;
+      /* column must not be fixed */
+      xassert(col->lb < col->ub);
+      /* start processing column */
+      if (col->ptr == NULL)
+      {  /* empty column */
+         ret = npp_empty_col(npp, col);
+         if (ret == 0)
+         {  /* column was fixed and deleted */
+#ifdef GLP_DEBUG
+            xprintf("N");
+#endif
+            return 0;
+         }
+         else if (ret == 1)
+         {  /* dual infeasibility */
+            return GLP_ENODFS;
+         }
+         else
+            xassert(ret != ret);
+      }
+      if (col->ptr->c_next == NULL)
+      {  /* column singleton */
+         row = col->ptr->row;
+         if (row->lb == row->ub)
+         {  /* equality constraint */
+            if (!col->is_int)
+slack:      {  /* implied slack variable */
+#ifdef GLP_DEBUG
+               xprintf("O");
+#endif
+               npp_implied_slack(npp, col);
+               /* column was deleted */
+               if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+               {  /* row became free due to implied slack variable */
+#ifdef GLP_DEBUG
+                  xprintf("P");
+#endif
+                  /* activate columns affected by row */
+                  for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+                     npp_activate_col(npp, aij->col);
+                  /* process free row */
+                  npp_free_row(npp, row);
+                  /* row was deleted */
+               }
+               else
+               {  /* row became inequality constraint; activate it
+                     since its length changed due to column deletion */
+                  npp_activate_row(npp, row);
+               }
+               return 0;
+            }
+         }
+         else
+         {  /* inequality constraint */
+            if (!col->is_int)
+            {  ret = npp_implied_free(npp, col);
+               if (ret == 0)
+               {  /* implied free variable */
+#ifdef GLP_DEBUG
+                  xprintf("Q");
+#endif
+                  /* column bounds were removed, row was replaced by
+                     equality constraint */
+                  goto slack;
+               }
+               else if (ret == 1)
+               {  /* column is not implied free variable, because its
+                     lower and/or upper bounds can be active */
+               }
+               else if (ret == 2)
+               {  /* dual infeasibility */
+                  return GLP_ENODFS;
+               }
+            }
+         }
+      }
+      /* column still exists */
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  npp_process_prob - perform basic LP/MIP processing
+*
+*  SYNOPSIS
+*
+*  #include "glpnpp.h"
+*  int npp_process_prob(NPP *npp, int hard);
+*
+*  DESCRIPTION
+*
+*  The routine npp_process_prob performs basic LP/MIP processing that
+*  currently includes:
+*
+*  1) initial LP/MIP processing (see the routine npp_clean_prob),
+*
+*  2) basic row processing (see the routine npp_process_row), and
+*
+*  3) basic column processing (see the routine npp_process_col).
+*
+*  If the flag hard is on, the routine attempts to improve current
+*  column bounds multiple times within the main processing loop, in
+*  which case this feature may take a time. Otherwise, if the flag hard
+*  is off, improving column bounds is performed only once at the end of
+*  the main loop. (Note that this feature is used for MIP only.)
+*
+*  The routine uses two sets: the set of active rows and the set of
+*  active columns. Rows/columns are marked by a flag (the field temp in
+*  NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
+*  in which case it is placed in the beginning of the row/column list;
+*  otherwise, if the flag is zero, the row/column is inactive, in which
+*  case it is placed in the end of the row/column list. If a row/column
+*  being currently processed may affect other rows/columns, the latters
+*  are activated for further processing.
+*
+*  RETURNS
+*
+*  0           success;
+*
+*  GLP_ENOPFS  primal/integer infeasibility detected;
+*
+*  GLP_ENODFS  dual infeasibility detected. */
+
+int npp_process_prob(NPP *npp, int hard)
+{     /* perform basic LP/MIP processing */
+      NPPROW *row;
+      NPPCOL *col;
+      int processing, ret;
+      /* perform initial LP/MIP processing */
+      npp_clean_prob(npp);
+      /* activate all remaining rows and columns */
+      for (row = npp->r_head; row != NULL; row = row->next)
+         row->temp = 1;
+      for (col = npp->c_head; col != NULL; col = col->next)
+         col->temp = 1;
+      /* main processing loop */
+      processing = 1;
+      while (processing)
+      {  processing = 0;
+         /* process all active rows */
+         for (;;)
+         {  row = npp->r_head;
+            if (row == NULL || !row->temp) break;
+            npp_deactivate_row(npp, row);
+            ret = npp_process_row(npp, row, hard);
+            if (ret != 0) goto done;
+            processing = 1;
+         }
+         /* process all active columns */
+         for (;;)
+         {  col = npp->c_head;
+            if (col == NULL || !col->temp) break;
+            npp_deactivate_col(npp, col);
+            ret = npp_process_col(npp, col);
+            if (ret != 0) goto done;
+            processing = 1;
+         }
+      }
+#if 1 /* 23/XII-2009 */
+      if (npp->sol == GLP_MIP && !hard)
+      {  /* improve current column bounds (optional) */
+         for (row = npp->r_head; row != NULL; row = row->next)
+         {  if (npp_improve_bounds(npp, row, 0) < 0)
+            {  ret = GLP_ENOPFS;
+               goto done;
+            }
+         }
+      }
+#endif
+      /* all seems ok */
+      ret = 0;
+done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
+#ifdef GLP_DEBUG
+      xprintf("\n");
+#endif
+      return ret;
+}
+
+/**********************************************************************/
+
+int npp_simplex(NPP *npp, const glp_smcp *parm)
+{     /* process LP prior to applying primal/dual simplex method */
+      int ret;
+      xassert(npp->sol == GLP_SOL);
+      xassert(parm == parm);
+      ret = npp_process_prob(npp, 0);
+      return ret;
+}
+
+/**********************************************************************/
+
+int npp_integer(NPP *npp, const glp_iocp *parm)
+{     /* process MIP prior to applying branch-and-bound method */
+      NPPROW *row, *prev_row;
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int count, ret;
+      xassert(npp->sol == GLP_MIP);
+      xassert(parm == parm);
+      /*==============================================================*/
+      /* perform basic MIP processing */
+      ret = npp_process_prob(npp, 1);
+      if (ret != 0) goto done;
+      /*==============================================================*/
+      /* binarize problem, if required */
+      if (parm->binarize)
+         npp_binarize_prob(npp);
+      /*==============================================================*/
+      /* identify hidden packing inequalities */
+      count = 0;
+      /* new rows will be added to the end of the row list, so we go
+         from the end to beginning of the row list */
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         /* skip free row */
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+         /* skip equality constraint */
+         if (row->lb == row->ub) continue;
+         /* skip row having less than two variables */
+         if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
+         /* skip row having non-binary variables */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  col = aij->col;
+            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+               break;
+         }
+         if (aij != NULL) continue;
+         count += npp_hidden_packing(npp, row);
+      }
+      if (count > 0)
+         xprintf("%d hidden packing inequaliti(es) were detected\n",
+            count);
+      /*==============================================================*/
+      /* identify hidden covering inequalities */
+      count = 0;
+      /* new rows will be added to the end of the row list, so we go
+         from the end to beginning of the row list */
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         /* skip free row */
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
+         /* skip equality constraint */
+         if (row->lb == row->ub) continue;
+         /* skip row having less than three variables */
+         if (row->ptr == NULL || row->ptr->r_next == NULL ||
+             row->ptr->r_next->r_next == NULL) continue;
+         /* skip row having non-binary variables */
+         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         {  col = aij->col;
+            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+               break;
+         }
+         if (aij != NULL) continue;
+         count += npp_hidden_covering(npp, row);
+      }
+      if (count > 0)
+         xprintf("%d hidden covering inequaliti(es) were detected\n",
+            count);
+      /*==============================================================*/
+      /* reduce inequality constraint coefficients */
+      count = 0;
+      /* new rows will be added to the end of the row list, so we go
+         from the end to beginning of the row list */
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         /* skip equality constraint */
+         if (row->lb == row->ub) continue;
+         count += npp_reduce_ineq_coef(npp, row);
+      }
+      if (count > 0)
+         xprintf("%d constraint coefficient(s) were reduced\n", count);
+      /*==============================================================*/
+#ifdef GLP_DEBUG
+      routine(npp);
+#endif
+      /*==============================================================*/
+      /* all seems ok */
+      ret = 0;
+done: return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpnpp06.c
===================================================================
--- deps/glpk/src/glpnpp06.c	(revision 9)
+++ deps/glpk/src/glpnpp06.c	(revision 9)
@@ -0,0 +1,1500 @@
+/* glpnpp06.c (translate feasibility problem to CNF-SAT) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpnpp.h"
+
+/***********************************************************************
+*  npp_sat_free_row - process free (unbounded) row
+*
+*  This routine processes row p, which is free (i.e. has no finite
+*  bounds):
+*
+*     -inf < sum a[p,j] x[j] < +inf.                                 (1)
+*
+*  The constraint (1) cannot be active and therefore it is redundant,
+*  so the routine simply removes it from the original problem. */
+
+void npp_sat_free_row(NPP *npp, NPPROW *p)
+{     /* the row should be free */
+      xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
+      /* remove the row from the problem */
+      npp_del_row(npp, p);
+      return;
+}
+
+/***********************************************************************
+*  npp_sat_fixed_col - process fixed column
+*
+*  This routine processes column q, which is fixed:
+*
+*     x[q] = s[q],                                                   (1)
+*
+*  where s[q] is a fixed column value.
+*
+*  The routine substitutes fixed value s[q] into constraint rows and
+*  then removes column x[q] from the original problem.
+*
+*  Substitution of x[q] = s[q] into row i gives:
+*
+*     L[i] <= sum a[i,j] x[j] <= U[i]   ==>
+*              j
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]   ==>
+*            j!=q
+*
+*     L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i]   ==>
+*            j!=q
+*
+*     L~[i] <= sum a[i,j] x[j] <= U~[i],
+*             j!=q
+*
+*  where
+*
+*     L~[i] = L[i] - a[i,q] s[q],                                    (2)
+*
+*     U~[i] = U[i] - a[i,q] s[q]                                     (3)
+*
+*  are, respectively, lower and upper bound of row i in the transformed
+*  problem.
+*
+*  On recovering solution x[q] is assigned the value of s[q]. */
+
+struct sat_fixed_col
+{     /* fixed column */
+      int q;
+      /* column reference number for variable x[q] */
+      int s;
+      /* value, at which x[q] is fixed */
+};
+
+static int rcv_sat_fixed_col(NPP *, void *);
+
+int npp_sat_fixed_col(NPP *npp, NPPCOL *q)
+{     struct sat_fixed_col *info;
+      NPPROW *i;
+      NPPAIJ *aij;
+      int temp;
+      /* the column should be fixed */
+      xassert(q->lb == q->ub);
+      /* create transformation stack entry */
+      info = npp_push_tse(npp,
+         rcv_sat_fixed_col, sizeof(struct sat_fixed_col));
+      info->q = q->j;
+      info->s = (int)q->lb;
+      xassert((double)info->s == q->lb);
+      /* substitute x[q] = s[q] into constraint rows */
+      if (info->s == 0)
+         goto skip;
+      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
+      {  i = aij->row;
+         if (i->lb != -DBL_MAX)
+         {  i->lb -= aij->val * (double)info->s;
+            temp = (int)i->lb;
+            if ((double)temp != i->lb)
+               return 1; /* integer arithmetic error */
+         }
+         if (i->ub != +DBL_MAX)
+         {  i->ub -= aij->val * (double)info->s;
+            temp = (int)i->ub;
+            if ((double)temp != i->ub)
+               return 2; /* integer arithmetic error */
+         }
+      }
+skip: /* remove the column from the problem */
+      npp_del_col(npp, q);
+      return 0;
+}
+
+static int rcv_sat_fixed_col(NPP *npp, void *info_)
+{     struct sat_fixed_col *info = info_;
+      npp->c_value[info->q] = (double)info->s;
+      return 0;
+}
+
+/***********************************************************************
+*  npp_sat_is_bin_comb - test if row is binary combination
+*
+*  This routine tests if the specified row is a binary combination,
+*  i.e. all its constraint coefficients are +1 and -1 and all variables
+*  are binary. If the test was passed, the routine returns non-zero,
+*  otherwise zero. */
+
+int npp_sat_is_bin_comb(NPP *npp, NPPROW *row)
+{     NPPCOL *col;
+      NPPAIJ *aij;
+      xassert(npp == npp);
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  if (!(aij->val == +1.0 || aij->val == -1.0))
+            return 0; /* non-unity coefficient */
+         col = aij->col;
+         if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
+            return 0; /* non-binary column */
+      }
+      return 1; /* test was passed */
+}
+
+/***********************************************************************
+*  npp_sat_num_pos_coef - determine number of positive coefficients
+*
+*  This routine returns the number of positive coefficients in the
+*  specified row. */
+
+int npp_sat_num_pos_coef(NPP *npp, NPPROW *row)
+{     NPPAIJ *aij;
+      int num = 0;
+      xassert(npp == npp);
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->val > 0.0)
+            num++;
+      }
+      return num;
+}
+
+/***********************************************************************
+*  npp_sat_num_neg_coef - determine number of negative coefficients
+*
+*  This routine returns the number of negative coefficients in the
+*  specified row. */
+
+int npp_sat_num_neg_coef(NPP *npp, NPPROW *row)
+{     NPPAIJ *aij;
+      int num = 0;
+      xassert(npp == npp);
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->val < 0.0)
+            num++;
+      }
+      return num;
+}
+
+/***********************************************************************
+*  npp_sat_is_cover_ineq - test if row is covering inequality
+*
+*  The canonical form of a covering inequality is the following:
+*
+*     sum x[j] >= 1,                                                 (1)
+*   j in J
+*
+*  where all x[j] are binary variables.
+*
+*  In general case a covering inequality may have one of the following
+*  two forms:
+*
+*     sum  x[j] -  sum  x[j] >= 1 - |J-|,                            (2)
+*   j in J+      j in J-
+*
+*
+*     sum  x[j] -  sum  x[j] <= |J+| - 1.                            (3)
+*   j in J+      j in J-
+*
+*  Obviously, the inequality (2) can be transformed to the form (1) by
+*  substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+*  negation of variable x[j]. And the inequality (3) can be transformed
+*  to (2) by multiplying both left- and right-hand sides by -1.
+*
+*  This routine returns one of the following codes:
+*
+*  0, if the specified row is not a covering inequality;
+*
+*  1, if the specified row has the form (2);
+*
+*  2, if the specified row has the form (3). */
+
+int npp_sat_is_cover_ineq(NPP *npp, NPPROW *row)
+{     xassert(npp == npp);
+      if (row->lb != -DBL_MAX && row->ub == +DBL_MAX)
+      {  /* row is inequality of '>=' type */
+         if (npp_sat_is_bin_comb(npp, row))
+         {  /* row is a binary combination */
+            if (row->lb == 1.0 - npp_sat_num_neg_coef(npp, row))
+            {  /* row has the form (2) */
+               return 1;
+            }
+         }
+      }
+      else if (row->lb == -DBL_MAX && row->ub != +DBL_MAX)
+      {  /* row is inequality of '<=' type */
+         if (npp_sat_is_bin_comb(npp, row))
+         {  /* row is a binary combination */
+            if (row->ub == npp_sat_num_pos_coef(npp, row) - 1.0)
+            {  /* row has the form (3) */
+               return 2;
+            }
+         }
+      }
+      /* row is not a covering inequality */
+      return 0;
+}
+
+/***********************************************************************
+*  npp_sat_is_pack_ineq - test if row is packing inequality
+*
+*  The canonical form of a packing inequality is the following:
+*
+*     sum x[j] <= 1,                                                 (1)
+*   j in J
+*
+*  where all x[j] are binary variables.
+*
+*  In general case a packing inequality may have one of the following
+*  two forms:
+*
+*     sum  x[j] -  sum  x[j] <= 1 - |J-|,                            (2)
+*   j in J+      j in J-
+*
+*
+*     sum  x[j] -  sum  x[j] >= |J+| - 1.                            (3)
+*   j in J+      j in J-
+*
+*  Obviously, the inequality (2) can be transformed to the form (1) by
+*  substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+*  negation of variable x[j]. And the inequality (3) can be transformed
+*  to (2) by multiplying both left- and right-hand sides by -1.
+*
+*  This routine returns one of the following codes:
+*
+*  0, if the specified row is not a packing inequality;
+*
+*  1, if the specified row has the form (2);
+*
+*  2, if the specified row has the form (3). */
+
+int npp_sat_is_pack_ineq(NPP *npp, NPPROW *row)
+{     xassert(npp == npp);
+      if (row->lb == -DBL_MAX && row->ub != +DBL_MAX)
+      {  /* row is inequality of '<=' type */
+         if (npp_sat_is_bin_comb(npp, row))
+         {  /* row is a binary combination */
+            if (row->ub == 1.0 - npp_sat_num_neg_coef(npp, row))
+            {  /* row has the form (2) */
+               return 1;
+            }
+         }
+      }
+      else if (row->lb != -DBL_MAX && row->ub == +DBL_MAX)
+      {  /* row is inequality of '>=' type */
+         if (npp_sat_is_bin_comb(npp, row))
+         {  /* row is a binary combination */
+            if (row->lb == npp_sat_num_pos_coef(npp, row) - 1.0)
+            {  /* row has the form (3) */
+               return 2;
+            }
+         }
+      }
+      /* row is not a packing inequality */
+      return 0;
+}
+
+/***********************************************************************
+*  npp_sat_is_partn_eq - test if row is partitioning equality
+*
+*  The canonical form of a partitioning equality is the following:
+*
+*     sum x[j] = 1,                                                  (1)
+*   j in J
+*
+*  where all x[j] are binary variables.
+*
+*  In general case a partitioning equality may have one of the following
+*  two forms:
+*
+*     sum  x[j] -  sum  x[j] = 1 - |J-|,                             (2)
+*   j in J+      j in J-
+*
+*
+*     sum  x[j] -  sum  x[j] = |J+| - 1.                             (3)
+*   j in J+      j in J-
+*
+*  Obviously, the equality (2) can be transformed to the form (1) by
+*  substitution x[j] = 1 - x'[j] for all j in J-, where x'[j] is the
+*  negation of variable x[j]. And the equality (3) can be transformed
+*  to (2) by multiplying both left- and right-hand sides by -1.
+*
+*  This routine returns one of the following codes:
+*
+*  0, if the specified row is not a partitioning equality;
+*
+*  1, if the specified row has the form (2);
+*
+*  2, if the specified row has the form (3). */
+
+int npp_sat_is_partn_eq(NPP *npp, NPPROW *row)
+{     xassert(npp == npp);
+      if (row->lb == row->ub)
+      {  /* row is equality constraint */
+         if (npp_sat_is_bin_comb(npp, row))
+         {  /* row is a binary combination */
+            if (row->lb == 1.0 - npp_sat_num_neg_coef(npp, row))
+            {  /* row has the form (2) */
+               return 1;
+            }
+            if (row->ub == npp_sat_num_pos_coef(npp, row) - 1.0)
+            {  /* row has the form (3) */
+               return 2;
+            }
+         }
+      }
+      /* row is not a partitioning equality */
+      return 0;
+}
+
+/***********************************************************************
+*  npp_sat_reverse_row - multiply both sides of row by -1
+*
+*  This routines multiplies by -1 both left- and right-hand sides of
+*  the specified row:
+*
+*     L <= sum x[j] <= U,
+*
+*  that results in the following row:
+*
+*     -U <= sum (-x[j]) <= -L.
+*
+*  If no integer overflow occured, the routine returns zero, otherwise
+*  non-zero. */
+
+int npp_sat_reverse_row(NPP *npp, NPPROW *row)
+{     NPPAIJ *aij;
+      int temp, ret = 0;
+      double old_lb, old_ub;
+      xassert(npp == npp);
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  aij->val = -aij->val;
+         temp = (int)aij->val;
+         if ((double)temp != aij->val)
+            ret = 1;
+      }
+      old_lb = row->lb, old_ub = row->ub;
+      if (old_ub == +DBL_MAX)
+         row->lb = -DBL_MAX;
+      else
+      {  row->lb = -old_ub;
+         temp = (int)row->lb;
+         if ((double)temp != row->lb)
+            ret = 2;
+      }
+      if (old_lb == -DBL_MAX)
+         row->ub = +DBL_MAX;
+      else
+      {  row->ub = -old_lb;
+         temp = (int)row->ub;
+         if ((double)temp != row->ub)
+            ret = 3;
+      }
+      return ret;
+}
+
+/***********************************************************************
+*  npp_sat_split_pack - split packing inequality
+*
+*  Let there be given a packing inequality in canonical form:
+*
+*     sum  t[j] <= 1,                                                (1)
+*   j in J
+*
+*  where t[j] = x[j] or t[j] = 1 - x[j], x[j] is a binary variable.
+*  And let J = J1 U J2 is a partition of the set of literals. Then the
+*  inequality (1) is obviously equivalent to the following two packing
+*  inequalities:
+*
+*     sum  t[j] <= y       <-->   sum  t[j] + (1 - y) <= 1,          (2)
+*   j in J1                     j in J1
+*
+*     sum  t[j] <= 1 - y   <-->   sum  t[j] + y       <= 1,          (3)
+*   j in J2                     j in J2
+*
+*  where y is a new binary variable added to the transformed problem.
+*
+*  Assuming that the specified row is a packing inequality (1), this
+*  routine constructs the set J1 by including there first nlit literals
+*  (terms) from the specified row, and the set J2 = J \ J1. Then the
+*  routine creates a new row, which corresponds to inequality (2), and
+*  replaces the specified row with inequality (3). */
+
+NPPROW *npp_sat_split_pack(NPP *npp, NPPROW *row, int nlit)
+{     NPPROW *rrr;
+      NPPCOL *col;
+      NPPAIJ *aij;
+      int k;
+      /* original row should be packing inequality (1) */
+      xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+      /* and nlit should be less than the number of literals (terms)
+         in the original row */
+      xassert(0 < nlit && nlit < npp_row_nnz(npp, row));
+      /* create new row corresponding to inequality (2) */
+      rrr = npp_add_row(npp);
+      rrr->lb = -DBL_MAX, rrr->ub = 1.0;
+      /* move first nlit literals (terms) from the original row to the
+         new row; the original row becomes inequality (3) */
+      for (k = 1; k <= nlit; k++)
+      {  aij = row->ptr;
+         xassert(aij != NULL);
+         /* add literal to the new row */
+         npp_add_aij(npp, rrr, aij->col, aij->val);
+         /* correct rhs */
+         if (aij->val < 0.0)
+            rrr->ub -= 1.0, row->ub += 1.0;
+         /* remove literal from the original row */
+         npp_del_aij(npp, aij);
+      }
+      /* create new binary variable y */
+      col = npp_add_col(npp);
+      col->is_int = 1, col->lb = 0.0, col->ub = 1.0;
+      /* include literal (1 - y) in the new row */
+      npp_add_aij(npp, rrr, col, -1.0);
+      rrr->ub -= 1.0;
+      /* include literal y in the original row */
+      npp_add_aij(npp, row, col, +1.0);
+      return rrr;
+}
+
+/***********************************************************************
+*  npp_sat_encode_pack - encode packing inequality
+*
+*  Given a packing inequality in canonical form:
+*
+*     sum  t[j] <= 1,                                                (1)
+*   j in J
+*
+*  where t[j] = x[j] or t[j] = 1 - x[j], x[j] is a binary variable,
+*  this routine translates it to CNF by replacing it with the following
+*  equivalent set of edge packing inequalities:
+*
+*     t[j] + t[k] <= 1   for all j, k in J, j != k.                  (2)
+*
+*  Then the routine transforms each edge packing inequality (2) to
+*  corresponding covering inequality (that encodes two-literal clause)
+*  by multiplying both its part by -1:
+*
+*     - t[j] - t[k] >= -1   <-->   (1 - t[j]) + (1 - t[k]) >= 1.     (3)
+*
+*  On exit the routine removes the original row from the problem. */
+
+void npp_sat_encode_pack(NPP *npp, NPPROW *row)
+{     NPPROW *rrr;
+      NPPAIJ *aij, *aik;
+      /* original row should be packing inequality (1) */
+      xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+      /* create equivalent system of covering inequalities (3) */
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  /* due to symmetry only one of inequalities t[j] + t[k] <= 1
+            and t[k] <= t[j] <= 1 can be considered */
+         for (aik = aij->r_next; aik != NULL; aik = aik->r_next)
+         {  /* create edge packing inequality (2) */
+            rrr = npp_add_row(npp);
+            rrr->lb = -DBL_MAX, rrr->ub = 1.0;
+            npp_add_aij(npp, rrr, aij->col, aij->val);
+            if (aij->val < 0.0)
+               rrr->ub -= 1.0;
+            npp_add_aij(npp, rrr, aik->col, aik->val);
+            if (aik->val < 0.0)
+               rrr->ub -= 1.0;
+            /* and transform it to covering inequality (3) */
+            npp_sat_reverse_row(npp, rrr);
+            xassert(npp_sat_is_cover_ineq(npp, rrr) == 1);
+         }
+      }
+      /* remove the original row from the problem */
+      npp_del_row(npp, row);
+      return;
+}
+
+/***********************************************************************
+*  npp_sat_encode_sum2 - encode 2-bit summation
+*
+*  Given a set containing two literals x and y this routine encodes
+*  the equality
+*
+*     x + y = s + 2 * c,                                             (1)
+*
+*  where
+*
+*     s = (x + y) % 2                                                (2)
+*
+*  is a binary variable modeling the low sum bit, and
+*
+*     c = (x + y) / 2                                                (3)
+*
+*  is a binary variable modeling the high (carry) sum bit. */
+
+void npp_sat_encode_sum2(NPP *npp, NPPLSE *set, NPPSED *sed)
+{     NPPROW *row;
+      int x, y, s, c;
+      /* the set should contain exactly two literals */
+      xassert(set != NULL);
+      xassert(set->next != NULL);
+      xassert(set->next->next == NULL);
+      sed->x = set->lit;
+      xassert(sed->x.neg == 0 || sed->x.neg == 1);
+      sed->y = set->next->lit;
+      xassert(sed->y.neg == 0 || sed->y.neg == 1);
+      sed->z.col = NULL, sed->z.neg = 0;
+      /* perform encoding s = (x + y) % 2 */
+      sed->s = npp_add_col(npp);
+      sed->s->is_int = 1, sed->s->lb = 0.0, sed->s->ub = 1.0;
+      for (x = 0; x <= 1; x++)
+      {  for (y = 0; y <= 1; y++)
+         {  for (s = 0; s <= 1; s++)
+            {  if ((x + y) % 2 != s)
+               {  /* generate CNF clause to disable infeasible
+                     combination */
+                  row = npp_add_row(npp);
+                  row->lb = 1.0, row->ub = +DBL_MAX;
+                  if (x == sed->x.neg)
+                     npp_add_aij(npp, row, sed->x.col, +1.0);
+                  else
+                  {  npp_add_aij(npp, row, sed->x.col, -1.0);
+                     row->lb -= 1.0;
+                  }
+                  if (y == sed->y.neg)
+                     npp_add_aij(npp, row, sed->y.col, +1.0);
+                  else
+                  {  npp_add_aij(npp, row, sed->y.col, -1.0);
+                     row->lb -= 1.0;
+                  }
+                  if (s == 0)
+                     npp_add_aij(npp, row, sed->s, +1.0);
+                  else
+                  {  npp_add_aij(npp, row, sed->s, -1.0);
+                     row->lb -= 1.0;
+                  }
+               }
+            }
+         }
+      }
+      /* perform encoding c = (x + y) / 2 */
+      sed->c = npp_add_col(npp);
+      sed->c->is_int = 1, sed->c->lb = 0.0, sed->c->ub = 1.0;
+      for (x = 0; x <= 1; x++)
+      {  for (y = 0; y <= 1; y++)
+         {  for (c = 0; c <= 1; c++)
+            {  if ((x + y) / 2 != c)
+               {  /* generate CNF clause to disable infeasible
+                     combination */
+                  row = npp_add_row(npp);
+                  row->lb = 1.0, row->ub = +DBL_MAX;
+                  if (x == sed->x.neg)
+                     npp_add_aij(npp, row, sed->x.col, +1.0);
+                  else
+                  {  npp_add_aij(npp, row, sed->x.col, -1.0);
+                     row->lb -= 1.0;
+                  }
+                  if (y == sed->y.neg)
+                     npp_add_aij(npp, row, sed->y.col, +1.0);
+                  else
+                  {  npp_add_aij(npp, row, sed->y.col, -1.0);
+                     row->lb -= 1.0;
+                  }
+                  if (c == 0)
+                     npp_add_aij(npp, row, sed->c, +1.0);
+                  else
+                  {  npp_add_aij(npp, row, sed->c, -1.0);
+                     row->lb -= 1.0;
+                  }
+               }
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  npp_sat_encode_sum3 - encode 3-bit summation
+*
+*  Given a set containing at least three literals this routine chooses
+*  some literals x, y, z from that set and encodes the equality
+*
+*     x + y + z = s + 2 * c,                                         (1)
+*
+*  where
+*
+*     s = (x + y + z) % 2                                            (2)
+*
+*  is a binary variable modeling the low sum bit, and
+*
+*     c = (x + y + z) / 2                                            (3)
+*
+*  is a binary variable modeling the high (carry) sum bit. */
+
+void npp_sat_encode_sum3(NPP *npp, NPPLSE *set, NPPSED *sed)
+{     NPPROW *row;
+      int x, y, z, s, c;
+      /* the set should contain at least three literals */
+      xassert(set != NULL);
+      xassert(set->next != NULL);
+      xassert(set->next->next != NULL);
+      sed->x = set->lit;
+      xassert(sed->x.neg == 0 || sed->x.neg == 1);
+      sed->y = set->next->lit;
+      xassert(sed->y.neg == 0 || sed->y.neg == 1);
+      sed->z = set->next->next->lit;
+      xassert(sed->z.neg == 0 || sed->z.neg == 1);
+      /* perform encoding s = (x + y + z) % 2 */
+      sed->s = npp_add_col(npp);
+      sed->s->is_int = 1, sed->s->lb = 0.0, sed->s->ub = 1.0;
+      for (x = 0; x <= 1; x++)
+      {  for (y = 0; y <= 1; y++)
+         {  for (z = 0; z <= 1; z++)
+            {  for (s = 0; s <= 1; s++)
+               {  if ((x + y + z) % 2 != s)
+                  {  /* generate CNF clause to disable infeasible
+                        combination */
+                     row = npp_add_row(npp);
+                     row->lb = 1.0, row->ub = +DBL_MAX;
+                     if (x == sed->x.neg)
+                        npp_add_aij(npp, row, sed->x.col, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->x.col, -1.0);
+                        row->lb -= 1.0;
+                     }
+                     if (y == sed->y.neg)
+                        npp_add_aij(npp, row, sed->y.col, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->y.col, -1.0);
+                        row->lb -= 1.0;
+                     }
+                     if (z == sed->z.neg)
+                        npp_add_aij(npp, row, sed->z.col, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->z.col, -1.0);
+                        row->lb -= 1.0;
+                     }
+                     if (s == 0)
+                        npp_add_aij(npp, row, sed->s, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->s, -1.0);
+                        row->lb -= 1.0;
+                     }
+                  }
+               }
+            }
+         }
+      }
+      /* perform encoding c = (x + y + z) / 2 */
+      sed->c = npp_add_col(npp);
+      sed->c->is_int = 1, sed->c->lb = 0.0, sed->c->ub = 1.0;
+      for (x = 0; x <= 1; x++)
+      {  for (y = 0; y <= 1; y++)
+         {  for (z = 0; z <= 1; z++)
+            {  for (c = 0; c <= 1; c++)
+               {  if ((x + y + z) / 2 != c)
+                  {  /* generate CNF clause to disable infeasible
+                        combination */
+                     row = npp_add_row(npp);
+                     row->lb = 1.0, row->ub = +DBL_MAX;
+                     if (x == sed->x.neg)
+                        npp_add_aij(npp, row, sed->x.col, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->x.col, -1.0);
+                        row->lb -= 1.0;
+                     }
+                     if (y == sed->y.neg)
+                        npp_add_aij(npp, row, sed->y.col, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->y.col, -1.0);
+                        row->lb -= 1.0;
+                     }
+                     if (z == sed->z.neg)
+                        npp_add_aij(npp, row, sed->z.col, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->z.col, -1.0);
+                        row->lb -= 1.0;
+                     }
+                     if (c == 0)
+                        npp_add_aij(npp, row, sed->c, +1.0);
+                     else
+                     {  npp_add_aij(npp, row, sed->c, -1.0);
+                        row->lb -= 1.0;
+                     }
+                  }
+               }
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  npp_sat_encode_sum_ax - encode linear combination of 0-1 variables
+*
+*  PURPOSE
+*
+*  Given a linear combination of binary variables:
+*
+*     sum a[j] x[j],                                                 (1)
+*      j
+*
+*  which is the linear form of the specified row, this routine encodes
+*  (i.e. translates to CNF) the following equality:
+*
+*                        n
+*     sum |a[j]| t[j] = sum 2**(k-1) * y[k],                         (2)
+*      j                k=1
+*
+*  where t[j] = x[j] (if a[j] > 0) or t[j] = 1 - x[j] (if a[j] < 0),
+*  and y[k] is either t[j] or a new literal created by the routine or
+*  a constant zero. Note that the sum in the right-hand side of (2) can
+*  be thought as a n-bit representation of the sum in the left-hand
+*  side, which is a non-negative integer number.
+*
+*  ALGORITHM
+*
+*  First, the number of bits, n, sufficient to represent any value in
+*  the left-hand side of (2) is determined. Obviously, n is the number
+*  of bits sufficient to represent the sum (sum |a[j]|).
+*
+*  Let
+*
+*               n
+*     |a[j]| = sum 2**(k-1) b[j,k],                                  (3)
+*              k=1
+*
+*  where b[j,k] is k-th bit in a n-bit representation of |a[j]|. Then
+*
+*                          m            n
+*     sum |a[j]| * t[j] = sum 2**(k-1) sum b[j,k] * t[j].            (4)
+*      j                  k=1          j=1
+*
+*  Introducing the set
+*
+*     J[k] = { j : b[j,k] = 1 }                                      (5)
+*
+*  allows rewriting (4) as follows:
+*
+*                          n
+*     sum |a[j]| * t[j] = sum 2**(k-1)  sum    t[j].                 (6)
+*      j                  k=1         j in J[k]
+*
+*  Thus, our goal is to provide |J[k]| <= 1 for all k, in which case
+*  we will have the representation (1).
+*
+*  Let |J[k]| = 2, i.e. J[k] has exactly two literals u and v. In this
+*  case we can apply the following transformation:
+*
+*     u + v = s + 2 * c,                                             (7)
+*
+*  where s and c are, respectively, low (sum) and high (carry) bits of
+*  the sum of two bits. This allows to replace two literals u and v in
+*  J[k] by one literal s, and carry out literal c to J[k+1].
+*
+*  If |J[k]| >= 3, i.e. J[k] has at least three literals u, v, and w,
+*  we can apply the following transformation:
+*
+*     u + v + w = s + 2 * c.                                         (8)
+*
+*  Again, literal s replaces literals u, v, and w in J[k], and literal
+*  c goes into J[k+1].
+*
+*  On exit the routine stores each literal from J[k] in element y[k],
+*  1 <= k <= n. If J[k] is empty, y[k] is set to constant false.
+*
+*  RETURNS
+*
+*  The routine returns n, the number of literals in the right-hand side
+*  of (2), 0 <= n <= NBIT_MAX. If the sum (sum |a[j]|) is too large, so
+*  more than NBIT_MAX (= 31) literals are needed to encode the original
+*  linear combination, the routine returns a negative value. */
+
+#define NBIT_MAX 31
+/* maximal number of literals in the right hand-side of (2) */
+
+static NPPLSE *remove_lse(NPP *npp, NPPLSE *set, NPPCOL *col)
+{     /* remove specified literal from specified literal set */
+      NPPLSE *lse, *prev = NULL;
+      for (lse = set; lse != NULL; prev = lse, lse = lse->next)
+         if (lse->lit.col == col) break;
+      xassert(lse != NULL);
+      if (prev == NULL)
+         set = lse->next;
+      else
+         prev->next = lse->next;
+      dmp_free_atom(npp->pool, lse, sizeof(NPPLSE));
+      return set;
+}
+
+int npp_sat_encode_sum_ax(NPP *npp, NPPROW *row, NPPLIT y[])
+{     NPPAIJ *aij;
+      NPPLSE *set[1+NBIT_MAX], *lse;
+      NPPSED sed;
+      int k, n, temp;
+      double sum;
+      /* compute the sum (sum |a[j]|) */
+      sum = 0.0;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+         sum += fabs(aij->val);
+      /* determine n, the number of bits in the sum */
+      temp = (int)sum;
+      if ((double)temp != sum)
+         return -1; /* integer arithmetic error */
+      for (n = 0; temp > 0; n++, temp >>= 1);
+      xassert(0 <= n && n <= NBIT_MAX);
+      /* build initial sets J[k], 1 <= k <= n; see (5) */
+      /* set[k] is a pointer to the list of literals in J[k] */
+      for (k = 1; k <= n; k++)
+         set[k] = NULL;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  temp = (int)fabs(aij->val);
+         xassert((int)temp == fabs(aij->val));
+         for (k = 1; temp > 0; k++, temp >>= 1)
+         {  if (temp & 1)
+            {  xassert(k <= n);
+               lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+               lse->lit.col = aij->col;
+               lse->lit.neg = (aij->val > 0.0 ? 0 : 1);
+               lse->next = set[k];
+               set[k] = lse;
+            }
+         }
+      }
+      /* main transformation loop */
+      for (k = 1; k <= n; k++)
+      {  /* reduce J[k] and set y[k] */
+         for (;;)
+         {  if (set[k] == NULL)
+            {  /* J[k] is empty */
+               /* set y[k] to constant false */
+               y[k].col = NULL, y[k].neg = 0;
+               break;
+            }
+            if (set[k]->next == NULL)
+            {  /* J[k] contains one literal */
+               /* set y[k] to that literal */
+               y[k] = set[k]->lit;
+               dmp_free_atom(npp->pool, set[k], sizeof(NPPLSE));
+               break;
+            }
+            if (set[k]->next->next == NULL)
+            {  /* J[k] contains two literals */
+               /* apply transformation (7) */
+               npp_sat_encode_sum2(npp, set[k], &sed);
+            }
+            else
+            {  /* J[k] contains at least three literals */
+               /* apply transformation (8) */
+               npp_sat_encode_sum3(npp, set[k], &sed);
+               /* remove third literal from set[k] */
+               set[k] = remove_lse(npp, set[k], sed.z.col);
+            }
+            /* remove second literal from set[k] */
+            set[k] = remove_lse(npp, set[k], sed.y.col);
+            /* remove first literal from set[k] */
+            set[k] = remove_lse(npp, set[k], sed.x.col);
+            /* include new literal s to set[k] */
+            lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+            lse->lit.col = sed.s, lse->lit.neg = 0;
+            lse->next = set[k];
+            set[k] = lse;
+            /* include new literal c to set[k+1] */
+            xassert(k < n); /* FIXME: can "overflow" happen? */
+            lse = dmp_get_atom(npp->pool, sizeof(NPPLSE));
+            lse->lit.col = sed.c, lse->lit.neg = 0;
+            lse->next = set[k+1];
+            set[k+1] = lse;
+         }
+      }
+      return n;
+}
+
+/***********************************************************************
+*  npp_sat_normalize_clause - normalize clause
+*
+*  This routine normalizes the specified clause, which is a disjunction
+*  of literals, by replacing multiple literals, which refer to the same
+*  binary variable, with a single literal.
+*
+*  On exit the routine returns the number of literals in the resulting
+*  clause. However, if the specified clause includes both a literal and
+*  its negation, the routine returns a negative value meaning that the
+*  clause is equivalent to the value true. */
+
+int npp_sat_normalize_clause(NPP *npp, int size, NPPLIT lit[])
+{     int j, k, new_size;
+      xassert(npp == npp);
+      xassert(size >= 0);
+      new_size = 0;
+      for (k = 1; k <= size; k++)
+      {  for (j = 1; j <= new_size; j++)
+         {  if (lit[k].col == lit[j].col)
+            {  /* lit[k] refers to the same variable as lit[j], which
+                  is already included in the resulting clause */
+               if (lit[k].neg == lit[j].neg)
+               {  /* ignore lit[k] due to the idempotent law */
+                  goto skip;
+               }
+               else
+               {  /* lit[k] is NOT lit[j]; the clause is equivalent to
+                     the value true */
+                  return -1;
+               }
+            }
+         }
+         /* include lit[k] in the resulting clause */
+         lit[++new_size] = lit[k];
+skip:    ;
+      }
+      return new_size;
+}
+
+/***********************************************************************
+*  npp_sat_encode_clause - translate clause to cover inequality
+*
+*  Given a clause
+*
+*     OR  t[j],                                                      (1)
+*   j in J
+*
+*  where t[j] is a literal, i.e. t[j] = x[j] or t[j] = NOT x[j], this
+*  routine translates it to the following equivalent cover inequality,
+*  which is added to the transformed problem:
+*
+*     sum t[j] >= 1,                                                 (2)
+*   j in J
+*
+*  where t[j] = x[j] or t[j] = 1 - x[j].
+*
+*  If necessary, the clause should be normalized before a call to this
+*  routine. */
+
+NPPROW *npp_sat_encode_clause(NPP *npp, int size, NPPLIT lit[])
+{     NPPROW *row;
+      int k;
+      xassert(size >= 1);
+      row = npp_add_row(npp);
+      row->lb = 1.0, row->ub = +DBL_MAX;
+      for (k = 1; k <= size; k++)
+      {  xassert(lit[k].col != NULL);
+         if (lit[k].neg == 0)
+            npp_add_aij(npp, row, lit[k].col, +1.0);
+         else if (lit[k].neg == 1)
+         {  npp_add_aij(npp, row, lit[k].col, -1.0);
+            row->lb -= 1.0;
+         }
+         else
+            xassert(lit != lit);
+      }
+      return row;
+}
+
+/***********************************************************************
+*  npp_sat_encode_geq - encode "not less than" constraint
+*
+*  PURPOSE
+*
+*  This routine translates to CNF the following constraint:
+*
+*      n
+*     sum 2**(k-1) * y[k] >= b,                                      (1)
+*     k=1
+*
+*  where y[k] is either a literal (i.e. y[k] = x[k] or y[k] = 1 - x[k])
+*  or constant false (zero), b is a given lower bound.
+*
+*  ALGORITHM
+*
+*  If b < 0, the constraint is redundant, so assume that b >= 0. Let
+*
+*          n
+*     b = sum 2**(k-1) b[k],                                         (2)
+*         k=1
+*
+*  where b[k] is k-th binary digit of b. (Note that if b >= 2**n and
+*  therefore cannot be represented in the form (2), the constraint (1)
+*  is infeasible.) In this case the condition (1) is equivalent to the
+*  following condition:
+*
+*     y[n] y[n-1] ... y[2] y[1] >= b[n] b[n-1] ... b[2] b[1],        (3)
+*
+*  where ">=" is understood lexicographically.
+*
+*  Algorithmically the condition (3) can be tested as follows:
+*
+*     for (k = n; k >= 1; k--)
+*     {  if (y[k] < b[k])
+*           y is less than b;
+*        if (y[k] > b[k])
+*           y is greater than b;
+*     }
+*     y is equal to b;
+*
+*  Thus, y is less than b iff there exists k, 1 <= k <= n, for which
+*  the following condition is satisfied:
+*
+*     y[n] = b[n] AND ... AND y[k+1] = b[k+1] AND y[k] < b[k].       (4)
+*
+*  Negating the condition (4) we have that y is not less than b iff for
+*  all k, 1 <= k <= n, the following condition is satisfied:
+*
+*     y[n] != b[n] OR ... OR y[k+1] != b[k+1] OR y[k] >= b[k].       (5)
+*
+*  Note that if b[k] = 0, the literal y[k] >= b[k] is always true, in
+*  which case the entire clause (5) is true and can be omitted.
+*
+*  RETURNS
+*
+*  Normally the routine returns zero. However, if the constraint (1) is
+*  infeasible, the routine returns non-zero. */
+
+int npp_sat_encode_geq(NPP *npp, int n, NPPLIT y[], int rhs)
+{     NPPLIT lit[1+NBIT_MAX];
+      int j, k, size, temp, b[1+NBIT_MAX];
+      xassert(0 <= n && n <= NBIT_MAX);
+      /* if the constraint (1) is redundant, do nothing */
+      if (rhs < 0)
+         return 0;
+      /* determine binary digits of b according to (2) */
+      for (k = 1, temp = rhs; k <= n; k++, temp >>= 1)
+         b[k] = temp & 1;
+      if (temp != 0)
+      {  /* b >= 2**n; the constraint (1) is infeasible */
+         return 1;
+      }
+      /* main transformation loop */
+      for (k = 1; k <= n; k++)
+      {  /* build the clause (5) for current k */
+         size = 0; /* clause size = number of literals */
+         /* add literal y[k] >= b[k] */
+         if (b[k] == 0)
+         {  /* b[k] = 0 -> the literal is true */
+            goto skip;
+         }
+         else if (y[k].col == NULL)
+         {  /* y[k] = 0, b[k] = 1 -> the literal is false */
+            xassert(y[k].neg == 0);
+         }
+         else
+         {  /* add literal y[k] = 1 */
+            lit[++size] = y[k];
+         }
+         for (j = k+1; j <= n; j++)
+         {  /* add literal y[j] != b[j] */
+            if (y[j].col == NULL)
+            {  xassert(y[j].neg == 0);
+               if (b[j] == 0)
+               {  /* y[j] = 0, b[j] = 0 -> the literal is false */
+                  continue;
+               }
+               else
+               {  /* y[j] = 0, b[j] = 1 -> the literal is true */
+                  goto skip;
+               }
+            }
+            else
+            {  lit[++size] = y[j];
+               if (b[j] != 0)
+                  lit[size].neg = 1 - lit[size].neg;
+            }
+         }
+         /* normalize the clause */
+         size = npp_sat_normalize_clause(npp, size, lit);
+         if (size < 0)
+         {  /* the clause is equivalent to the value true */
+            goto skip;
+         }
+         if (size == 0)
+         {  /* the clause is equivalent to the value false; this means
+               that the constraint (1) is infeasible */
+            return 2;
+         }
+         /* translate the clause to corresponding cover inequality */
+         npp_sat_encode_clause(npp, size, lit);
+skip:    ;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  npp_sat_encode_leq - encode "not greater than" constraint
+*
+*  PURPOSE
+*
+*  This routine translates to CNF the following constraint:
+*
+*      n
+*     sum 2**(k-1) * y[k] <= b,                                      (1)
+*     k=1
+*
+*  where y[k] is either a literal (i.e. y[k] = x[k] or y[k] = 1 - x[k])
+*  or constant false (zero), b is a given upper bound.
+*
+*  ALGORITHM
+*
+*  If b < 0, the constraint is infeasible, so assume that b >= 0. Let
+*
+*          n
+*     b = sum 2**(k-1) b[k],                                         (2)
+*         k=1
+*
+*  where b[k] is k-th binary digit of b. (Note that if b >= 2**n and
+*  therefore cannot be represented in the form (2), the constraint (1)
+*  is redundant.) In this case the condition (1) is equivalent to the
+*  following condition:
+*
+*     y[n] y[n-1] ... y[2] y[1] <= b[n] b[n-1] ... b[2] b[1],        (3)
+*
+*  where "<=" is understood lexicographically.
+*
+*  Algorithmically the condition (3) can be tested as follows:
+*
+*     for (k = n; k >= 1; k--)
+*     {  if (y[k] < b[k])
+*           y is less than b;
+*        if (y[k] > b[k])
+*           y is greater than b;
+*     }
+*     y is equal to b;
+*
+*  Thus, y is greater than b iff there exists k, 1 <= k <= n, for which
+*  the following condition is satisfied:
+*
+*     y[n] = b[n] AND ... AND y[k+1] = b[k+1] AND y[k] > b[k].       (4)
+*
+*  Negating the condition (4) we have that y is not greater than b iff
+*  for all k, 1 <= k <= n, the following condition is satisfied:
+*
+*     y[n] != b[n] OR ... OR y[k+1] != b[k+1] OR y[k] <= b[k].       (5)
+*
+*  Note that if b[k] = 1, the literal y[k] <= b[k] is always true, in
+*  which case the entire clause (5) is true and can be omitted.
+*
+*  RETURNS
+*
+*  Normally the routine returns zero. However, if the constraint (1) is
+*  infeasible, the routine returns non-zero. */
+
+int npp_sat_encode_leq(NPP *npp, int n, NPPLIT y[], int rhs)
+{     NPPLIT lit[1+NBIT_MAX];
+      int j, k, size, temp, b[1+NBIT_MAX];
+      xassert(0 <= n && n <= NBIT_MAX);
+      /* check if the constraint (1) is infeasible */
+      if (rhs < 0)
+         return 1;
+      /* determine binary digits of b according to (2) */
+      for (k = 1, temp = rhs; k <= n; k++, temp >>= 1)
+         b[k] = temp & 1;
+      if (temp != 0)
+      {  /* b >= 2**n; the constraint (1) is redundant */
+         return 0;
+      }
+      /* main transformation loop */
+      for (k = 1; k <= n; k++)
+      {  /* build the clause (5) for current k */
+         size = 0; /* clause size = number of literals */
+         /* add literal y[k] <= b[k] */
+         if (b[k] == 1)
+         {  /* b[k] = 1 -> the literal is true */
+            goto skip;
+         }
+         else if (y[k].col == NULL)
+         {  /* y[k] = 0, b[k] = 0 -> the literal is true */
+            xassert(y[k].neg == 0);
+            goto skip;
+         }
+         else
+         {  /* add literal y[k] = 0 */
+            lit[++size] = y[k];
+            lit[size].neg = 1 - lit[size].neg;
+         }
+         for (j = k+1; j <= n; j++)
+         {  /* add literal y[j] != b[j] */
+            if (y[j].col == NULL)
+            {  xassert(y[j].neg == 0);
+               if (b[j] == 0)
+               {  /* y[j] = 0, b[j] = 0 -> the literal is false */
+                  continue;
+               }
+               else
+               {  /* y[j] = 0, b[j] = 1 -> the literal is true */
+                  goto skip;
+               }
+            }
+            else
+            {  lit[++size] = y[j];
+               if (b[j] != 0)
+                  lit[size].neg = 1 - lit[size].neg;
+            }
+         }
+         /* normalize the clause */
+         size = npp_sat_normalize_clause(npp, size, lit);
+         if (size < 0)
+         {  /* the clause is equivalent to the value true */
+            goto skip;
+         }
+         if (size == 0)
+         {  /* the clause is equivalent to the value false; this means
+               that the constraint (1) is infeasible */
+            return 2;
+         }
+         /* translate the clause to corresponding cover inequality */
+         npp_sat_encode_clause(npp, size, lit);
+skip:    ;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  npp_sat_encode_row - encode constraint (row) of general type
+*
+*  PURPOSE
+*
+*  This routine translates to CNF the following constraint (row):
+*
+*     L <= sum a[j] x[j] <= U,                                       (1)
+*           j
+*
+*  where all x[j] are binary variables.
+*
+*  ALGORITHM
+*
+*  First, the routine performs substitution x[j] = t[j] for j in J+
+*  and x[j] = 1 - t[j] for j in J-, where J+ = { j : a[j] > 0 } and
+*  J- = { j : a[j] < 0 }. This gives:
+*
+*     L <=  sum  a[j] t[j] +   sum  a[j] (1 - t[j]) <= U  ==>
+*         j in J+            j in J-
+*
+*     L' <= sum |a[j]| t[j] <= U',                                   (2)
+*            j
+*
+*  where
+*
+*     L' = L -   sum  a[j],   U' = U -   sum  a[j].                  (3)
+*              j in J-                 j in J-
+*
+*  (Actually only new bounds L' and U' are computed.)
+*
+*  Then the routine translates to CNF the following equality:
+*
+*                        n
+*     sum |a[j]| t[j] = sum 2**(k-1) * y[k],                         (4)
+*      j                k=1
+*
+*  where y[k] is either some t[j] or a new literal or a constant zero
+*  (see the routine npp_sat_encode_sum_ax).
+*
+*  Finally, the routine translates to CNF the following conditions:
+*
+*      n
+*     sum 2**(k-1) * y[k] >= L'                                      (5)
+*     k=1
+*
+*  and
+*
+*      n
+*     sum 2**(k-1) * y[k] <= U'                                      (6)
+*     k=1
+*
+*  (see the routines npp_sat_encode_geq and npp_sat_encode_leq).
+*
+*  All resulting clauses are encoded as cover inequalities and included
+*  into the transformed problem.
+*
+*  Note that on exit the routine removes the specified constraint (row)
+*  from the original problem.
+*
+*  RETURNS
+*
+*  The routine returns one of the following codes:
+*
+*  0 - translation was successful;
+*  1 - constraint (1) was found infeasible;
+*  2 - integer arithmetic error occured. */
+
+int npp_sat_encode_row(NPP *npp, NPPROW *row)
+{     NPPAIJ *aij;
+      NPPLIT y[1+NBIT_MAX];
+      int n, rhs;
+      double lb, ub;
+      /* the row should not be free */
+      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
+      /* compute new bounds L' and U' (3) */
+      lb = row->lb;
+      ub = row->ub;
+      for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+      {  if (aij->val < 0.0)
+         {  if (lb != -DBL_MAX)
+               lb -= aij->val;
+            if (ub != -DBL_MAX)
+               ub -= aij->val;
+         }
+      }
+      /* encode the equality (4) */
+      n = npp_sat_encode_sum_ax(npp, row, y);
+      if (n < 0)
+         return 2; /* integer arithmetic error */
+      /* encode the condition (5) */
+      if (lb != -DBL_MAX)
+      {  rhs = (int)lb;
+         if ((double)rhs != lb)
+            return 2; /* integer arithmetic error */
+         if (npp_sat_encode_geq(npp, n, y, rhs) != 0)
+            return 1; /* original constraint is infeasible */
+      }
+      /* encode the condition (6) */
+      if (ub != +DBL_MAX)
+      {  rhs = (int)ub;
+         if ((double)rhs != ub)
+            return 2; /* integer arithmetic error */
+         if (npp_sat_encode_leq(npp, n, y, rhs) != 0)
+            return 1; /* original constraint is infeasible */
+      }
+      /* remove the specified row from the problem */
+      npp_del_row(npp, row);
+      return 0;
+}
+
+/***********************************************************************
+*  npp_sat_encode_prob - encode 0-1 feasibility problem
+*
+*  This routine translates the specified 0-1 feasibility problem to an
+*  equivalent SAT-CNF problem.
+*
+*  N.B. Currently this is a very crude implementation.
+*
+*  RETURNS
+*
+*  0           success;
+*
+*  GLP_ENOPFS  primal/integer infeasibility detected;
+*
+*  GLP_ERANGE  integer overflow occured. */
+
+int npp_sat_encode_prob(NPP *npp)
+{     NPPROW *row, *next_row, *prev_row;
+      NPPCOL *col, *next_col;
+      int cover = 0, pack = 0, partn = 0, ret;
+      /* process and remove free rows */
+      for (row = npp->r_head; row != NULL; row = next_row)
+      {  next_row = row->next;
+         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
+            npp_sat_free_row(npp, row);
+      }
+      /* process and remove fixed columns */
+      for (col = npp->c_head; col != NULL; col = next_col)
+      {  next_col = col->next;
+         if (col->lb == col->ub)
+            xassert(npp_sat_fixed_col(npp, col) == 0);
+      }
+      /* only binary variables should remain */
+      for (col = npp->c_head; col != NULL; col = col->next)
+         xassert(col->is_int && col->lb == 0.0 && col->ub == 1.0);
+      /* new rows may be added to the end of the row list, so we walk
+         from the end to beginning of the list */
+      for (row = npp->r_tail; row != NULL; row = prev_row)
+      {  prev_row = row->prev;
+         /* process special cases */
+         ret = npp_sat_is_cover_ineq(npp, row);
+         if (ret != 0)
+         {  /* row is covering inequality */
+            cover++;
+            /* since it already encodes a clause, just transform it to
+               canonical form */
+            if (ret == 2)
+            {  xassert(npp_sat_reverse_row(npp, row) == 0);
+               ret = npp_sat_is_cover_ineq(npp, row);
+            }
+            xassert(ret == 1);
+            continue;
+         }
+         ret = npp_sat_is_partn_eq(npp, row);
+         if (ret != 0)
+         {  /* row is partitioning equality */
+            NPPROW *cov;
+            NPPAIJ *aij;
+            partn++;
+            /* transform it to canonical form */
+            if (ret == 2)
+            {  xassert(npp_sat_reverse_row(npp, row) == 0);
+               ret = npp_sat_is_partn_eq(npp, row);
+            }
+            xassert(ret == 1);
+            /* and split it into covering and packing inequalities,
+               both in canonical forms */
+            cov = npp_add_row(npp);
+            cov->lb = row->lb, cov->ub = +DBL_MAX;
+            for (aij = row->ptr; aij != NULL; aij = aij->r_next)
+               npp_add_aij(npp, cov, aij->col, aij->val);
+            xassert(npp_sat_is_cover_ineq(npp, cov) == 1);
+            /* the cover inequality already encodes a clause and do
+               not need any further processing */
+            row->lb = -DBL_MAX;
+            xassert(npp_sat_is_pack_ineq(npp, row) == 1);
+            /* the packing inequality will be processed below */
+            pack--;
+         }
+         ret = npp_sat_is_pack_ineq(npp, row);
+         if (ret != 0)
+         {  /* row is packing inequality */
+            NPPROW *rrr;
+            int nlit, desired_nlit = 4;
+            pack++;
+            /* transform it to canonical form */
+            if (ret == 2)
+            {  xassert(npp_sat_reverse_row(npp, row) == 0);
+               ret = npp_sat_is_pack_ineq(npp, row);
+            }
+            xassert(ret == 1);
+            /* process the packing inequality */
+            for (;;)
+            {  /* determine the number of literals in the remaining
+                  inequality */
+               nlit = npp_row_nnz(npp, row);
+               if (nlit <= desired_nlit)
+                  break;
+               /* split the current inequality into one having not more
+                  than desired_nlit literals and remaining one */
+               rrr = npp_sat_split_pack(npp, row, desired_nlit-1);
+               /* translate the former inequality to CNF and remove it
+                  from the original problem */
+               npp_sat_encode_pack(npp, rrr);
+            }
+            /* translate the remaining inequality to CNF and remove it
+               from the original problem */
+            npp_sat_encode_pack(npp, row);
+            continue;
+         }
+         /* translate row of general type to CNF and remove it from the
+            original problem */
+         ret = npp_sat_encode_row(npp, row);
+         if (ret == 0)
+            ;
+         else if (ret == 1)
+            ret = GLP_ENOPFS;
+         else if (ret == 2)
+            ret = GLP_ERANGE;
+         else
+            xassert(ret != ret);
+         if (ret != 0)
+            goto done;
+      }
+      ret = 0;
+      if (cover != 0)
+         xprintf("%d covering inequalities\n", cover);
+      if (pack != 0)
+         xprintf("%d packing inequalities\n", pack);
+      if (partn != 0)
+         xprintf("%d partitioning equalities\n", partn);
+done: return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpqmd.c
===================================================================
--- deps/glpk/src/glpqmd.c	(revision 9)
+++ deps/glpk/src/glpqmd.c	(revision 9)
@@ -0,0 +1,584 @@
+/* glpqmd.c (quotient minimum degree algorithm) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES
+*  GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK:
+*
+*  ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE
+*  POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981.
+*
+*  THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS
+*  OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU,
+*  UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA.
+*
+*  The translation was made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpqmd.h"
+
+/***********************************************************************
+*  NAME
+*
+*  genqmd - GENeral Quotient Minimum Degree algorithm
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
+*     int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+*     int qsize[], int qlink[], int *nofsub);
+*
+*  PURPOSE
+*
+*  This routine implements the minimum degree algorithm. It makes use
+*  of the implicit representation of the elimination graph by quotient
+*  graphs, and the notion of indistinguishable nodes.
+*
+*  CAUTION
+*
+*  The adjancy vector adjncy will be destroyed.
+*
+*  INPUT PARAMETERS
+*
+*  neqns  - number of equations;
+*  (xadj, adjncy) -
+*           the adjancy structure.
+*
+*  OUTPUT PARAMETERS
+*
+*  perm   - the minimum degree ordering;
+*  invp   - the inverse of perm.
+*
+*  WORKING PARAMETERS
+*
+*  deg    - the degree vector. deg[i] is negative means node i has been
+*           numbered;
+*  marker - a marker vector, where marker[i] is negative means node i
+*           has been merged with another nodeand thus can be ignored;
+*  rchset - vector used for the reachable set;
+*  nbrhd  - vector used for neighborhood set;
+*  qsize  - vector used to store the size of indistinguishable
+*           supernodes;
+*  qlink  - vector used to store indistinguishable nodes, i, qlink[i],
+*           qlink[qlink[i]], ... are the members of the supernode
+*           represented by i.
+*
+*  PROGRAM SUBROUTINES
+*
+*  qmdrch, qmdqt, qmdupd.
+***********************************************************************/
+
+void genqmd(int *_neqns, int xadj[], int adjncy[], int perm[],
+      int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+      int qsize[], int qlink[], int *_nofsub)
+{     int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num,
+         nump1, nxnode, rchsze, search, thresh;
+#     define neqns  (*_neqns)
+#     define nofsub (*_nofsub)
+      /* Initialize degree vector and other working variables. */
+      mindeg = neqns;
+      nofsub = 0;
+      for (node = 1; node <= neqns; node++)
+      {  perm[node] = node;
+         invp[node] = node;
+         marker[node] = 0;
+         qsize[node] = 1;
+         qlink[node] = 0;
+         ndeg = xadj[node+1] - xadj[node];
+         deg[node] = ndeg;
+         if (ndeg < mindeg) mindeg = ndeg;
+      }
+      num = 0;
+      /* Perform threshold search to get a node of min degree.
+         Variable search point to where search should start. */
+s200: search = 1;
+      thresh = mindeg;
+      mindeg = neqns;
+s300: nump1 = num + 1;
+      if (nump1 > search) search = nump1;
+      for (j = search; j <= neqns; j++)
+      {  node = perm[j];
+         if (marker[node] >= 0)
+         {  ndeg = deg[node];
+            if (ndeg <= thresh) goto s500;
+            if (ndeg < mindeg) mindeg = ndeg;
+         }
+      }
+      goto s200;
+      /* Node has minimum degree. Find its reachable sets by calling
+         qmdrch. */
+s500: search = j;
+      nofsub += deg[node];
+      marker[node] = 1;
+      qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze,
+         nbrhd);
+      /* Eliminate all nodes indistinguishable from node. They are given
+         by node, qlink[node], ... . */
+      nxnode = node;
+s600: num++;
+      np = invp[nxnode];
+      ip = perm[num];
+      perm[np] = ip;
+      invp[ip] = np;
+      perm[num] = nxnode;
+      invp[nxnode] = num;
+      deg[nxnode] = -1;
+      nxnode = qlink[nxnode];
+      if (nxnode > 0) goto s600;
+      if (rchsze > 0)
+      {  /* Update the degrees of the nodes in the reachable set and
+            identify indistinguishable nodes. */
+         qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink,
+            marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]);
+         /* Reset marker value of nodes in reach set. Update threshold
+            value for cyclic search. Also call qmdqt to form new
+            quotient graph. */
+         marker[node] = 0;
+         for (irch = 1; irch <= rchsze; irch++)
+         {  inode = rchset[irch];
+            if (marker[inode] >= 0)
+            {  marker[inode] = 0;
+               ndeg = deg[inode];
+               if (ndeg < mindeg) mindeg = ndeg;
+               if (ndeg <= thresh)
+               {  mindeg = thresh;
+                  thresh = ndeg;
+                  search = invp[inode];
+               }
+            }
+         }
+         if (nhdsze > 0)
+            qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd);
+      }
+      if (num < neqns) goto s300;
+      return;
+#     undef neqns
+#     undef nofsub
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdrch - Quotient MD ReaCHable set
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
+*     int marker[], int *rchsze, int rchset[], int *nhdsze,
+*     int nbrhd[]);
+*
+*  PURPOSE
+*
+*  This subroutine determines the reachable set of a node through a
+*  given subset. The adjancy structure is assumed to be stored in a
+*  quotient graph format.
+* 
+*  INPUT PARAMETERS
+*
+*  root   - the given node not in the subset;
+*  (xadj, adjncy) -
+*           the adjancy structure pair;
+*  deg    - the degree vector. deg[i] < 0 means the node belongs to the
+*           given subset.
+*
+*  OUTPUT PARAMETERS
+*
+*  (rchsze, rchset) -
+*           the reachable set;
+*  (nhdsze, nbrhd) -
+*           the neighborhood set.
+*
+*  UPDATED PARAMETERS
+*
+*  marker - the marker vector for reach and nbrhd sets. > 0 means the
+*           node is in reach set. < 0 means the node has been merged
+*           with others in the quotient or it is in nbrhd set.
+***********************************************************************/
+
+void qmdrch(int *_root, int xadj[], int adjncy[], int deg[],
+      int marker[], int *_rchsze, int rchset[], int *_nhdsze,
+      int nbrhd[])
+{     int i, istop, istrt, j, jstop, jstrt, nabor, node;
+#     define root   (*_root)
+#     define rchsze (*_rchsze)
+#     define nhdsze (*_nhdsze)
+      /* Loop through the neighbors of root in the quotient graph. */
+      nhdsze = 0;
+      rchsze = 0;
+      istrt = xadj[root];
+      istop = xadj[root+1] - 1;
+      if (istop < istrt) return;
+      for (i = istrt; i <= istop; i++)
+      {  nabor = adjncy[i];
+         if (nabor == 0) return;
+         if (marker[nabor] == 0)
+         {  if (deg[nabor] >= 0)
+            {  /* Include nabor into the reachable set. */
+               rchsze++;
+               rchset[rchsze] = nabor;
+               marker[nabor] = 1;
+               goto s600;
+            }
+            /* nabor has been eliminated. Find nodes reachable from
+               it. */
+            marker[nabor] = -1;
+            nhdsze++;
+            nbrhd[nhdsze] = nabor;
+s300:       jstrt = xadj[nabor];
+            jstop = xadj[nabor+1] - 1;
+            for (j = jstrt; j <= jstop; j++)
+            {  node = adjncy[j];
+               nabor = - node;
+               if (node < 0) goto s300;
+               if (node == 0) goto s600;
+               if (marker[node] == 0)
+               {  rchsze++;
+                  rchset[rchsze] = node;
+                  marker[node] = 1;
+               }
+            }
+         }
+s600:    ;
+      }
+      return;
+#     undef root
+#     undef rchsze
+#     undef nhdsze
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdqt - Quotient MD Quotient graph Transformation
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
+*     int *rchsze, int rchset[], int nbrhd[]);
+*
+*  PURPOSE
+*
+*  This subroutine performs the quotient graph transformation after a
+*  node has been eliminated.
+*
+*  INPUT PARAMETERS
+*
+*  root   - the node just eliminated. It becomes the representative of
+*           the new supernode;
+*  (xadj, adjncy) -
+*           the adjancy structure;
+*  (rchsze, rchset) -
+*           the reachable set of root in the old quotient graph;
+*  nbrhd  - the neighborhood set which will be merged with root to form
+*           the new supernode;
+*  marker - the marker vector.
+*
+*  UPDATED PARAMETERS
+*
+*  adjncy - becomes the adjncy of the quotient graph.
+***********************************************************************/
+
+void qmdqt(int *_root, int xadj[], int adjncy[], int marker[],
+      int *_rchsze, int rchset[], int nbrhd[])
+{     int inhd, irch, j, jstop, jstrt, link, nabor, node;
+#     define root   (*_root)
+#     define rchsze (*_rchsze)
+      irch = 0;
+      inhd = 0;
+      node = root;
+s100: jstrt = xadj[node];
+      jstop = xadj[node+1] - 2;
+      if (jstop >= jstrt)
+      {  /* Place reach nodes into the adjacent list of node. */
+         for (j = jstrt; j <= jstop; j++)
+         {  irch++;
+            adjncy[j] = rchset[irch];
+            if (irch >= rchsze) goto s400;
+         }
+      }
+      /* Link to other space provided by the nbrhd set. */
+      link = adjncy[jstop+1];
+      node = - link;
+      if (link >= 0)
+      {  inhd++;
+         node = nbrhd[inhd];
+         adjncy[jstop+1] = - node;
+      }
+      goto s100;
+      /* All reachable nodes have been saved. End the adjacent list.
+         Add root to the neighborhood list of each node in the reach
+         set. */
+s400: adjncy[j+1] = 0;
+      for (irch = 1; irch <= rchsze; irch++)
+      {  node = rchset[irch];
+         if (marker[node] >= 0)
+         {  jstrt = xadj[node];
+            jstop = xadj[node+1] - 1;
+            for (j = jstrt; j <= jstop; j++)
+            {  nabor = adjncy[j];
+               if (marker[nabor] < 0)
+               {  adjncy[j] = root;
+                  goto s600;
+               }
+            }
+         }
+s600:    ;
+      }
+      return;
+#     undef root
+#     undef rchsze
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdupd - Quotient MD UPDate
+*
+*  SYNOPSIS
+*
+*  #include "glpqmd.h"
+*  void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
+*     int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+*     int nbrhd[]);
+*
+*  PURPOSE
+*
+*  This routine performs degree update for a set of nodes in the minimum
+*  degree algorithm.
+*
+*  INPUT PARAMETERS
+*
+*  (xadj, adjncy) -
+*           the adjancy structure;
+*  (nlist, list) -
+*           the list of nodes whose degree has to be updated.
+*
+*  UPDATED PARAMETERS
+*
+*  deg    - the degree vector;
+*  qsize  - size of indistinguishable supernodes;
+*  qlink  - linked list for indistinguishable nodes;
+*  marker - used to mark those nodes in reach/nbrhd sets.
+*
+*  WORKING PARAMETERS
+*
+*  rchset - the reachable set;
+*  nbrhd  - the neighborhood set.
+*
+*  PROGRAM SUBROUTINES
+*
+*  qmdmrg.
+***********************************************************************/
+
+void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[],
+      int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+      int nbrhd[])
+{     int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark,
+         nabor, nhdsze, node, rchsze;
+#     define nlist  (*_nlist)
+      /* Find all eliminated supernodes that are adjacent to some nodes
+         in the given list. Put them into (nhdsze, nbrhd). deg0 contains
+         the number of nodes in the list. */
+      if (nlist <= 0) return;
+      deg0 = 0;
+      nhdsze = 0;
+      for (il = 1; il <= nlist; il++)
+      {  node = list[il];
+         deg0 += qsize[node];
+         jstrt = xadj[node];
+         jstop = xadj[node+1] - 1;
+         for (j = jstrt; j <= jstop; j++)
+         {  nabor = adjncy[j];
+            if (marker[nabor] == 0 && deg[nabor] < 0)
+            {  marker[nabor] = -1;
+               nhdsze++;
+               nbrhd[nhdsze] = nabor;
+            }
+         }
+      }
+      /* Merge indistinguishable nodes in the list by calling the
+         subroutine qmdmrg. */
+      if (nhdsze > 0)
+         qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, &deg0, &nhdsze,
+            nbrhd, rchset, &nbrhd[nhdsze+1]);
+      /* Find the new degrees of the nodes that have not been merged. */
+      for (il = 1; il <= nlist; il++)
+      {  node = list[il];
+         mark = marker[node];
+         if (mark == 0 || mark == 1)
+         {  marker[node] = 2;
+            qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset,
+               &nhdsze, nbrhd);
+            deg1 = deg0;
+            if (rchsze > 0)
+            {  for (irch = 1; irch <= rchsze; irch++)
+               {  inode = rchset[irch];
+                  deg1 += qsize[inode];
+                  marker[inode] = 0;
+               }
+            }
+            deg[node] = deg1 - 1;
+            if (nhdsze > 0)
+            {  for (inhd = 1; inhd <= nhdsze; inhd++)
+               {  inode = nbrhd[inhd];
+                  marker[inode] = 0;
+               }
+            }
+         }
+      }
+      return;
+#     undef nlist
+}
+
+/***********************************************************************
+*  NAME
+*
+*  qmdmrg - Quotient MD MeRGe
+*
+*  SYNOPSIS
+*
+*  #include "qmdmrg.h"
+*  void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+*     int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
+*     int rchset[], int ovrlp[]);
+*
+*  PURPOSE
+*
+*  This routine merges indistinguishable nodes in the minimum degree
+*  ordering algorithm. It also computes the new degrees of these new
+*  supernodes.
+*
+*  INPUT PARAMETERS
+*
+*  (xadj, adjncy) -
+*           the adjancy structure;
+*  deg0   - the number of nodes in the given set;
+*  (nhdsze, nbrhd) -
+*           the set of eliminated supernodes adjacent to some nodes in
+*           the set.
+*
+*  UPDATED PARAMETERS
+*
+*  deg    - the degree vector;
+*  qsize  - size of indistinguishable nodes;
+*  qlink  - linked list for indistinguishable nodes;
+*  marker - the given set is given by those nodes with marker value set
+*           to 1. Those nodes with degree updated will have marker value
+*           set to 2.
+*
+*  WORKING PARAMETERS
+*
+*  rchset - the reachable set;
+*  ovrlp  - temp vector to store the intersection of two reachable sets.
+***********************************************************************/
+
+void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+      int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[],
+      int rchset[], int ovrlp[])
+{     int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode,
+         mark, mrgsze, nabor, node, novrlp, rchsze, root;
+#     define deg0   (*_deg0)
+#     define nhdsze (*_nhdsze)
+      /* Initialization. */
+      if (nhdsze <= 0) return;
+      for (inhd = 1; inhd <= nhdsze; inhd++)
+      {  root = nbrhd[inhd];
+         marker[root] = 0;
+      }
+      /* Loop through each eliminated supernode in the set
+         (nhdsze, nbrhd). */
+      for (inhd = 1; inhd <= nhdsze; inhd++)
+      {  root = nbrhd[inhd];
+         marker[root] = -1;
+         rchsze = 0;
+         novrlp = 0;
+         deg1 = 0;
+s200:    jstrt = xadj[root];
+         jstop = xadj[root+1] - 1;
+         /* Determine the reachable set and its intersection with the
+            input reachable set. */
+         for (j = jstrt; j <= jstop; j++)
+         {  nabor = adjncy[j];
+            root = - nabor;
+            if (nabor < 0) goto s200;
+            if (nabor == 0) break;
+            mark = marker[nabor];
+            if (mark == 0)
+            {  rchsze++;
+               rchset[rchsze] = nabor;
+               deg1 += qsize[nabor];
+               marker[nabor] = 1;
+            }
+            else if (mark == 1)
+            {  novrlp++;
+               ovrlp[novrlp] = nabor;
+               marker[nabor] = 2;
+            }
+         }
+         /* From the overlapped set, determine the nodes that can be
+            merged together. */
+         head = 0;
+         mrgsze = 0;
+         for (iov = 1; iov <= novrlp; iov++)
+         {  node = ovrlp[iov];
+            jstrt = xadj[node];
+            jstop = xadj[node+1] - 1;
+            for (j = jstrt; j <= jstop; j++)
+            {  nabor = adjncy[j];
+               if (marker[nabor] == 0)
+               {  marker[node] = 1;
+                  goto s1100;
+               }
+            }
+            /* Node belongs to the new merged supernode. Update the
+               vectors qlink and qsize. */
+            mrgsze += qsize[node];
+            marker[node] = -1;
+            lnode = node;
+s900:       link = qlink[lnode];
+            if (link > 0)
+            {  lnode = link;
+               goto s900;
+            }
+            qlink[lnode] = head;
+            head = node;
+s1100:      ;
+         }
+         if (head > 0)
+         {  qsize[head] = mrgsze;
+            deg[head] = deg0 + deg1 - 1;
+            marker[head] = 2;
+         }
+         /* Reset marker values. */
+         root = nbrhd[inhd];
+         marker[root] = 0;
+         if (rchsze > 0)
+         {  for (irch = 1; irch <= rchsze; irch++)
+            {  node = rchset[irch];
+               marker[node] = 0;
+            }
+         }
+      }
+      return;
+#     undef deg0
+#     undef nhdsze
+}
+
+/* eof */
Index: deps/glpk/src/glpqmd.h
===================================================================
--- deps/glpk/src/glpqmd.h	(revision 9)
+++ deps/glpk/src/glpqmd.h	(revision 9)
@@ -0,0 +1,59 @@
+/* glpqmd.h (quotient minimum degree algorithm) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPQMD_H
+#define GLPQMD_H
+
+#define genqmd _glp_qmd_genqmd
+void genqmd(int *neqns, int xadj[], int adjncy[], int perm[],
+      int invp[], int deg[], int marker[], int rchset[], int nbrhd[],
+      int qsize[], int qlink[], int *nofsub);
+/* GENeral Quotient Minimum Degree algorithm */
+
+#define qmdrch _glp_qmd_qmdrch
+void qmdrch(int *root, int xadj[], int adjncy[], int deg[],
+      int marker[], int *rchsze, int rchset[], int *nhdsze,
+      int nbrhd[]);
+/* Quotient MD ReaCHable set */
+
+#define qmdqt _glp_qmd_qmdqt
+void qmdqt(int *root, int xadj[], int adjncy[], int marker[],
+      int *rchsze, int rchset[], int nbrhd[]);
+/* Quotient MD Quotient graph Transformation */
+
+#define qmdupd _glp_qmd_qmdupd
+void qmdupd(int xadj[], int adjncy[], int *nlist, int list[],
+      int deg[], int qsize[], int qlink[], int marker[], int rchset[],
+      int nbrhd[]);
+/* Quotient MD UPDate */
+
+#define qmdmrg _glp_qmd_qmdmrg
+void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[],
+      int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[],
+      int rchset[], int ovrlp[]);
+/* Quotient MD MeRGe */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glprgr.c
===================================================================
--- deps/glpk/src/glprgr.c	(revision 9)
+++ deps/glpk/src/glprgr.c	(revision 9)
@@ -0,0 +1,165 @@
+/* glprgr.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glprgr.h"
+#define xfault xerror
+
+/***********************************************************************
+*  NAME
+*
+*  rgr_write_bmp16 - write 16-color raster image in BMP file format
+*
+*  SYNOPSIS
+*
+*  #include "glprgr.h"
+*  int rgr_write_bmp16(const char *fname, int m, int n, const char
+*     map[]);
+*
+*  DESCRIPTION
+*
+*  The routine rgr_write_bmp16 writes 16-color raster image in
+*  uncompressed BMP file format (Windows bitmap) to a binary file whose
+*  name is specified by the character string fname.
+*
+*  The parameters m and n specify, respectively, the number of rows and
+*  the numbers of columns (i.e. height and width) of the raster image.
+*
+*  The character array map has m*n elements. Elements map[0, ..., n-1]
+*  correspond to the first (top) scanline, elements map[n, ..., 2*n-1]
+*  correspond to the second scanline, etc.
+*
+*  Each element of the array map specifies a color of the corresponding
+*  pixel as 8-bit binary number XXXXIRGB, where four high-order bits (X)
+*  are ignored, I is high intensity bit, R is red color bit, G is green
+*  color bit, and B is blue color bit. Thus, all 16 possible colors are
+*  coded as following hexadecimal numbers:
+*
+*     0x00 = black         0x08 = dark gray
+*     0x01 = blue          0x09 = bright blue
+*     0x02 = green         0x0A = bright green
+*     0x03 = cyan          0x0B = bright cyan
+*     0x04 = red           0x0C = bright red
+*     0x05 = magenta       0x0D = bright magenta
+*     0x06 = brown         0x0E = yellow
+*     0x07 = light gray    0x0F = white
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero; otherwise, it prints
+*  an appropriate error message and returns non-zero. */
+
+static void put_byte(FILE *fp, int c)
+{     fputc(c, fp);
+      return;
+}
+
+static void put_word(FILE *fp, int w)
+{     /* big endian */
+      put_byte(fp, w);
+      put_byte(fp, w >> 8);
+      return;
+}
+
+static void put_dword(FILE *fp, int d)
+{     /* big endian */
+      put_word(fp, d);
+      put_word(fp, d >> 16);
+      return;
+}
+
+int rgr_write_bmp16(const char *fname, int m, int n, const char map[])
+{     FILE *fp;
+      int offset, bmsize, i, j, b, ret = 0;
+      if (!(1 <= m && m <= 32767))
+         xfault("rgr_write_bmp16: m = %d; invalid height\n", m);
+      if (!(1 <= n && n <= 32767))
+         xfault("rgr_write_bmp16: n = %d; invalid width\n", n);
+      fp = fopen(fname, "wb");
+      if (fp == NULL)
+      {  xprintf("rgr_write_bmp16: unable to create `%s' - %s\n",
+            fname, strerror(errno));
+         ret = 1;
+         goto fini;
+      }
+      offset = 14 + 40 + 16 * 4;
+      bmsize = (4 * n + 31) / 32;
+      /* struct BMPFILEHEADER (14 bytes) */
+      /* UINT bfType */          put_byte(fp, 'B'), put_byte(fp, 'M');
+      /* DWORD bfSize */         put_dword(fp, offset + bmsize * 4);
+      /* UINT bfReserved1 */     put_word(fp, 0);
+      /* UNIT bfReserved2 */     put_word(fp, 0);
+      /* DWORD bfOffBits */      put_dword(fp, offset);
+      /* struct BMPINFOHEADER (40 bytes) */
+      /* DWORD biSize */         put_dword(fp, 40);
+      /* LONG biWidth */         put_dword(fp, n);
+      /* LONG biHeight */        put_dword(fp, m);
+      /* WORD biPlanes */        put_word(fp, 1);
+      /* WORD biBitCount */      put_word(fp, 4);
+      /* DWORD biCompression */  put_dword(fp, 0 /* BI_RGB */);
+      /* DWORD biSizeImage */    put_dword(fp, 0);
+      /* LONG biXPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
+      /* LONG biYPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */);
+      /* DWORD biClrUsed */      put_dword(fp, 0);
+      /* DWORD biClrImportant */ put_dword(fp, 0);
+      /* struct RGBQUAD (16 * 4 = 64 bytes) */
+      /* CGA-compatible colors: */
+      /* 0x00 = black */         put_dword(fp, 0x000000);
+      /* 0x01 = blue */          put_dword(fp, 0x000080);
+      /* 0x02 = green */         put_dword(fp, 0x008000);
+      /* 0x03 = cyan */          put_dword(fp, 0x008080);
+      /* 0x04 = red */           put_dword(fp, 0x800000);
+      /* 0x05 = magenta */       put_dword(fp, 0x800080);
+      /* 0x06 = brown */         put_dword(fp, 0x808000);
+      /* 0x07 = light gray */    put_dword(fp, 0xC0C0C0);
+      /* 0x08 = dark gray */     put_dword(fp, 0x808080);
+      /* 0x09 = bright blue */   put_dword(fp, 0x0000FF);
+      /* 0x0A = bright green */  put_dword(fp, 0x00FF00);
+      /* 0x0B = bright cyan */   put_dword(fp, 0x00FFFF);
+      /* 0x0C = bright red */    put_dword(fp, 0xFF0000);
+      /* 0x0D = bright magenta */ put_dword(fp, 0xFF00FF);
+      /* 0x0E = yellow */        put_dword(fp, 0xFFFF00);
+      /* 0x0F = white */         put_dword(fp, 0xFFFFFF);
+      /* pixel data bits */
+      b = 0;
+      for (i = m - 1; i >= 0; i--)
+      {  for (j = 0; j < ((n + 7) / 8) * 8; j++)
+         {  b <<= 4;
+            b |= (j < n ? map[i * n + j] & 15 : 0);
+            if (j & 1) put_byte(fp, b);
+         }
+      }
+      fflush(fp);
+      if (ferror(fp))
+      {  xprintf("rgr_write_bmp16: write error on `%s' - %s\n",
+            fname, strerror(errno));
+         ret = 1;
+      }
+fini: if (fp != NULL) fclose(fp);
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glprgr.h
===================================================================
--- deps/glpk/src/glprgr.h	(revision 9)
+++ deps/glpk/src/glprgr.h	(revision 9)
@@ -0,0 +1,34 @@
+/* glprgr.h (raster graphics) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPRGR_H
+#define GLPRGR_H
+
+#define rgr_write_bmp16 _glp_rgr_write_bmp16
+int rgr_write_bmp16(const char *fname, int m, int n, const char map[]);
+/* write 16-color raster image in BMP file format */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glprng.h
===================================================================
--- deps/glpk/src/glprng.h	(revision 9)
+++ deps/glpk/src/glprng.h	(revision 9)
@@ -0,0 +1,68 @@
+/* glprng.h (pseudo-random number generator) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPRNG_H
+#define GLPRNG_H
+
+typedef struct RNG RNG;
+
+struct RNG
+{     /* Knuth's portable pseudo-random number generator */
+      int A[56];
+      /* pseudo-random values */
+      int *fptr;
+      /* the next A value to be exported */
+};
+
+#define rng_create_rand _glp_rng_create_rand
+RNG *rng_create_rand(void);
+/* create pseudo-random number generator */
+
+#define rng_init_rand _glp_rng_init_rand
+void rng_init_rand(RNG *rand, int seed);
+/* initialize pseudo-random number generator */
+
+#define rng_next_rand _glp_rng_next_rand
+int rng_next_rand(RNG *rand);
+/* obtain pseudo-random integer in the range [0, 2^31-1] */
+
+#define rng_unif_rand _glp_rng_unif_rand
+int rng_unif_rand(RNG *rand, int m);
+/* obtain pseudo-random integer in the range [0, m-1] */
+
+#define rng_delete_rand _glp_rng_delete_rand
+void rng_delete_rand(RNG *rand);
+/* delete pseudo-random number generator */
+
+#define rng_unif_01 _glp_rng_unif_01
+double rng_unif_01(RNG *rand);
+/* obtain pseudo-random number in the range [0, 1] */
+
+#define rng_uniform _glp_rng_uniform
+double rng_uniform(RNG *rand, double a, double b);
+/* obtain pseudo-random number in the range [a, b] */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glprng01.c
===================================================================
--- deps/glpk/src/glprng01.c	(revision 9)
+++ deps/glpk/src/glprng01.c	(revision 9)
@@ -0,0 +1,227 @@
+/* glprng01.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  This code is a modified version of the module GB_FLIP, a portable
+*  pseudo-random number generator. The original version of GB_FLIP is
+*  a part of The Stanford GraphBase developed by Donald E. Knuth (see
+*  http://www-cs-staff.stanford.edu/~knuth/sgb.html).
+*
+*  Note that all changes concern only external names, so this modified
+*  version produces exactly the same results as the original version.
+*
+*  Changes were made by Andrew Makhorin <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glprng.h"
+
+#if 0
+int A[56] = { -1 };
+#else
+#define A (rand->A)
+#endif
+/* pseudo-random values */
+
+#if 0
+int *fptr = A;
+#else
+#define fptr (rand->fptr)
+#endif
+/* the next A value to be exported */
+
+#define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF)
+/* difference modulo 2^31 */
+
+static int flip_cycle(RNG *rand)
+{     /* this is an auxiliary routine to do 55 more steps of the basic
+         recurrence, at high speed, and to reset fptr */
+      int *ii, *jj;
+      for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++)
+         *ii = mod_diff(*ii, *jj);
+      for (jj = &A[1]; ii <= &A[55]; ii++, jj++)
+         *ii = mod_diff(*ii, *jj);
+      fptr = &A[54];
+      return A[55];
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_create_rand - create pseudo-random number generator
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  RNG *rng_create_rand(void);
+*
+*  DESCRIPTION
+*
+*  The routine rng_create_rand creates and initializes a pseudo-random
+*  number generator.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the generator created. */
+
+RNG *rng_create_rand(void)
+{     RNG *rand;
+      int i;
+      rand = xmalloc(sizeof(RNG));
+      A[0] = -1;
+      for (i = 1; i <= 55; i++) A[i] = 0;
+      fptr = A;
+      rng_init_rand(rand, 1);
+      return rand;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_init_rand - initialize pseudo-random number generator
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  void rng_init_rand(RNG *rand, int seed);
+*
+*  DESCRIPTION
+*
+*  The routine rng_init_rand initializes the pseudo-random number
+*  generator. The parameter seed may be any integer number. Note that
+*  on creating the generator this routine is called with the parameter
+*  seed equal to 1. */
+
+void rng_init_rand(RNG *rand, int seed)
+{     int i;
+      int prev = seed, next = 1;
+      seed = prev = mod_diff(prev, 0);
+      A[55] = prev;
+      for (i = 21; i; i = (i + 21) % 55)
+      {  A[i] = next;
+         next = mod_diff(prev, next);
+         if (seed & 1)
+            seed = 0x40000000 + (seed >> 1);
+         else
+            seed >>= 1;
+         next = mod_diff(next, seed);
+         prev = A[i];
+      }
+      flip_cycle(rand);
+      flip_cycle(rand);
+      flip_cycle(rand);
+      flip_cycle(rand);
+      flip_cycle(rand);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  int rng_next_rand(RNG *rand);
+*
+*  RETURNS
+*
+*  The routine rng_next_rand returns a next pseudo-random integer which
+*  is uniformly distributed between 0 and 2^31-1, inclusive. The period
+*  length of the generated numbers is 2^85 - 2^30. The low order bits of
+*  the generated numbers are just as random as the high-order bits. */
+
+int rng_next_rand(RNG *rand)
+{     return
+         *fptr >= 0 ? *fptr-- : flip_cycle(rand);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_unif_rand - obtain pseudo-random integer in the range [0, m-1]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  int rng_unif_rand(RNG *rand, int m);
+*
+*  RETURNS
+*
+*  The routine rng_unif_rand returns a next pseudo-random integer which
+*  is uniformly distributed between 0 and m-1, inclusive, where m is any
+*  positive integer less than 2^31. */
+
+#define two_to_the_31 ((unsigned int)0x80000000)
+
+int rng_unif_rand(RNG *rand, int m)
+{     unsigned int t = two_to_the_31 - (two_to_the_31 % m);
+      int r;
+      xassert(m > 0);
+      do { r = rng_next_rand(rand); } while (t <= (unsigned int)r);
+      return r % m;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_delete_rand - delete pseudo-random number generator
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  void rng_delete_rand(RNG *rand);
+*
+*  DESCRIPTION
+*
+*  The routine rng_delete_rand frees all the memory allocated to the
+*  specified pseudo-random number generator. */
+
+void rng_delete_rand(RNG *rand)
+{     xfree(rand);
+      return;
+}
+
+/**********************************************************************/
+
+#if 0
+/* To be sure that this modified version produces the same results as
+   the original version, run this validation program. */
+
+int main(void)
+{     RNG *rand;
+      int j;
+      rand = rng_create_rand();
+      rng_init_rand(rand, -314159);
+      if (rng_next_rand(rand) != 119318998)
+      {  fprintf(stderr, "Failure on the first try!\n");
+         return -1;
+      }
+      for (j = 1; j <= 133; j++) rng_next_rand(rand);
+      if (rng_unif_rand(rand, 0x55555555) != 748103812)
+      {  fprintf(stderr, "Failure on the second try!\n");
+         return -2;
+      }
+      fprintf(stderr, "OK, the random-number generator routines seem to"
+         " work!\n");
+      rng_delete_rand(rand);
+      return 0;
+}
+#endif
+
+/* eof */
Index: deps/glpk/src/glprng02.c
===================================================================
--- deps/glpk/src/glprng02.c	(revision 9)
+++ deps/glpk/src/glprng02.c	(revision 9)
@@ -0,0 +1,76 @@
+/* glprng02.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glprng.h"
+#define xfault xerror
+
+/***********************************************************************
+*  NAME
+*
+*  rng_unif_01 - obtain pseudo-random number in the range [0, 1]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  double rng_unif_01(RNG *rand);
+*
+*  RETURNS
+*
+*  The routine rng_unif_01 returns a next pseudo-random number which is
+*  uniformly distributed in the range [0, 1]. */
+
+double rng_unif_01(RNG *rand)
+{     double x;
+      x = (double)rng_next_rand(rand) / 2147483647.0;
+      xassert(0.0 <= x && x <= 1.0);
+      return x;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  rng_uniform - obtain pseudo-random number in the range [a, b]
+*
+*  SYNOPSIS
+*
+*  #include "glprng.h"
+*  double rng_uniform(RNG *rand, double a, double b);
+*
+*  RETURNS
+*
+*  The routine rng_uniform returns a next pseudo-random number which is
+*  uniformly distributed in the range [a, b]. */
+
+double rng_uniform(RNG *rand, double a, double b)
+{     double x;
+      if (a >= b)
+         xfault("rng_uniform: a = %g, b = %g; invalid range\n", a, b);
+      x = rng_unif_01(rand);
+      x = a * (1.0 - x) + b * x;
+      xassert(a <= x && x <= b);
+      return x;
+}
+
+/* eof */
Index: deps/glpk/src/glpscf.c
===================================================================
--- deps/glpk/src/glpscf.c	(revision 9)
+++ deps/glpk/src/glpscf.c	(revision 9)
@@ -0,0 +1,634 @@
+/* glpscf.c (Schur complement factorization) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpscf.h"
+#define xfault xerror
+
+#define _GLPSCF_DEBUG 0
+
+#define eps 1e-10
+
+/***********************************************************************
+*  NAME
+*
+*  scf_create_it - create Schur complement factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  SCF *scf_create_it(int n_max);
+*
+*  DESCRIPTION
+*
+*  The routine scf_create_it creates the factorization of matrix C,
+*  which initially has no rows and columns.
+*
+*  The parameter n_max specifies the maximal order of matrix C to be
+*  factorized, 1 <= n_max <= 32767.
+*
+*  RETURNS
+*
+*  The routine scf_create_it returns a pointer to the structure SCF,
+*  which defines the factorization. */
+
+SCF *scf_create_it(int n_max)
+{     SCF *scf;
+#if _GLPSCF_DEBUG
+      xprintf("scf_create_it: warning: debug mode enabled\n");
+#endif
+      if (!(1 <= n_max && n_max <= 32767))
+         xfault("scf_create_it: n_max = %d; invalid parameter\n",
+            n_max);
+      scf = xmalloc(sizeof(SCF));
+      scf->n_max = n_max;
+      scf->n = 0;
+      scf->f = xcalloc(1 + n_max * n_max, sizeof(double));
+      scf->u = xcalloc(1 + n_max * (n_max + 1) / 2, sizeof(double));
+      scf->p = xcalloc(1 + n_max, sizeof(int));
+      scf->t_opt = SCF_TBG;
+      scf->rank = 0;
+#if _GLPSCF_DEBUG
+      scf->c = xcalloc(1 + n_max * n_max, sizeof(double));
+#else
+      scf->c = NULL;
+#endif
+      scf->w = xcalloc(1 + n_max, sizeof(double));
+      return scf;
+}
+
+/***********************************************************************
+*  The routine f_loc determines location of matrix element F[i,j] in
+*  the one-dimensional array f. */
+
+static int f_loc(SCF *scf, int i, int j)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      xassert(1 <= i && i <= n);
+      xassert(1 <= j && j <= n);
+      return (i - 1) * n_max + j;
+}
+
+/***********************************************************************
+*  The routine u_loc determines location of matrix element U[i,j] in
+*  the one-dimensional array u. */
+
+static int u_loc(SCF *scf, int i, int j)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      xassert(1 <= i && i <= n);
+      xassert(i <= j && j <= n);
+      return (i - 1) * n_max + j - i * (i - 1) / 2;
+}
+
+/***********************************************************************
+*  The routine bg_transform applies Bartels-Golub version of gaussian
+*  elimination to restore triangular structure of matrix U.
+*
+*  On entry matrix U has the following structure:
+*
+*        1       k         n
+*     1  * * * * * * * * * *
+*        . * * * * * * * * *
+*        . . * * * * * * * *
+*        . . . * * * * * * *
+*     k  . . . . * * * * * *
+*        . . . . . * * * * *
+*        . . . . . . * * * *
+*        . . . . . . . * * *
+*        . . . . . . . . * *
+*     n  . . . . # # # # # #
+*
+*  where '#' is a row spike to be eliminated.
+*
+*  Elements of n-th row are passed separately in locations un[k], ...,
+*  un[n]. On exit the content of the array un is destroyed.
+*
+*  REFERENCES
+*
+*  R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
+*  Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
+
+static void bg_transform(SCF *scf, int k, double un[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int j, k1, kj, kk, n1, nj;
+      double t;
+      xassert(1 <= k && k <= n);
+      /* main elimination loop */
+      for (k = k; k < n; k++)
+      {  /* determine location of U[k,k] */
+         kk = u_loc(scf, k, k);
+         /* determine location of F[k,1] */
+         k1 = f_loc(scf, k, 1);
+         /* determine location of F[n,1] */
+         n1 = f_loc(scf, n, 1);
+         /* if |U[k,k]| < |U[n,k]|, interchange k-th and n-th rows to
+            provide |U[k,k]| >= |U[n,k]| */
+         if (fabs(u[kk]) < fabs(un[k]))
+         {  /* interchange k-th and n-th rows of matrix U */
+            for (j = k, kj = kk; j <= n; j++, kj++)
+               t = u[kj], u[kj] = un[j], un[j] = t;
+            /* interchange k-th and n-th rows of matrix F to keep the
+               main equality F * C = U * P */
+            for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
+               t = f[kj], f[kj] = f[nj], f[nj] = t;
+         }
+         /* now |U[k,k]| >= |U[n,k]| */
+         /* if U[k,k] is too small in the magnitude, replace U[k,k] and
+            U[n,k] by exact zero */
+         if (fabs(u[kk]) < eps) u[kk] = un[k] = 0.0;
+         /* if U[n,k] is already zero, elimination is not needed */
+         if (un[k] == 0.0) continue;
+         /* compute gaussian multiplier t = U[n,k] / U[k,k] */
+         t = un[k] / u[kk];
+         /* apply gaussian elimination to nullify U[n,k] */
+         /* (n-th row of U) := (n-th row of U) - t * (k-th row of U) */
+         for (j = k+1, kj = kk+1; j <= n; j++, kj++)
+            un[j] -= t * u[kj];
+         /* (n-th row of F) := (n-th row of F) - t * (k-th row of F)
+            to keep the main equality F * C = U * P */
+         for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
+            f[nj] -= t * f[kj];
+      }
+      /* if U[n,n] is too small in the magnitude, replace it by exact
+         zero */
+      if (fabs(un[n]) < eps) un[n] = 0.0;
+      /* store U[n,n] in a proper location */
+      u[u_loc(scf, n, n)] = un[n];
+      return;
+}
+
+/***********************************************************************
+*  The routine givens computes the parameters of Givens plane rotation
+*  c = cos(teta) and s = sin(teta) such that:
+*
+*     ( c -s ) ( a )   ( r )
+*     (      ) (   ) = (   ) ,
+*     ( s  c ) ( b )   ( 0 )
+*
+*  where a and b are given scalars.
+*
+*  REFERENCES
+*
+*  G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */
+
+static void givens(double a, double b, double *c, double *s)
+{     double t;
+      if (b == 0.0)
+         (*c) = 1.0, (*s) = 0.0;
+      else if (fabs(a) <= fabs(b))
+         t = - a / b, (*s) = 1.0 / sqrt(1.0 + t * t), (*c) = (*s) * t;
+      else
+         t = - b / a, (*c) = 1.0 / sqrt(1.0 + t * t), (*s) = (*c) * t;
+      return;
+}
+
+/*----------------------------------------------------------------------
+*  The routine gr_transform applies Givens plane rotations to restore
+*  triangular structure of matrix U.
+*
+*  On entry matrix U has the following structure:
+*
+*        1       k         n
+*     1  * * * * * * * * * *
+*        . * * * * * * * * *
+*        . . * * * * * * * *
+*        . . . * * * * * * *
+*     k  . . . . * * * * * *
+*        . . . . . * * * * *
+*        . . . . . . * * * *
+*        . . . . . . . * * *
+*        . . . . . . . . * *
+*     n  . . . . # # # # # #
+*
+*  where '#' is a row spike to be eliminated.
+*
+*  Elements of n-th row are passed separately in locations un[k], ...,
+*  un[n]. On exit the content of the array un is destroyed.
+*
+*  REFERENCES
+*
+*  R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming
+*  Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */
+
+static void gr_transform(SCF *scf, int k, double un[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int j, k1, kj, kk, n1, nj;
+      double c, s;
+      xassert(1 <= k && k <= n);
+      /* main elimination loop */
+      for (k = k; k < n; k++)
+      {  /* determine location of U[k,k] */
+         kk = u_loc(scf, k, k);
+         /* determine location of F[k,1] */
+         k1 = f_loc(scf, k, 1);
+         /* determine location of F[n,1] */
+         n1 = f_loc(scf, n, 1);
+         /* if both U[k,k] and U[n,k] are too small in the magnitude,
+            replace them by exact zero */
+         if (fabs(u[kk]) < eps && fabs(un[k]) < eps)
+            u[kk] = un[k] = 0.0;
+         /* if U[n,k] is already zero, elimination is not needed */
+         if (un[k] == 0.0) continue;
+         /* compute the parameters of Givens plane rotation */
+         givens(u[kk], un[k], &c, &s);
+         /* apply Givens rotation to k-th and n-th rows of matrix U */
+         for (j = k, kj = kk; j <= n; j++, kj++)
+         {  double ukj = u[kj], unj = un[j];
+            u[kj] = c * ukj - s * unj;
+            un[j] = s * ukj + c * unj;
+         }
+         /* apply Givens rotation to k-th and n-th rows of matrix F
+            to keep the main equality F * C = U * P */
+         for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++)
+         {  double fkj = f[kj], fnj = f[nj];
+            f[kj] = c * fkj - s * fnj;
+            f[nj] = s * fkj + c * fnj;
+         }
+      }
+      /* if U[n,n] is too small in the magnitude, replace it by exact
+         zero */
+      if (fabs(un[n]) < eps) un[n] = 0.0;
+      /* store U[n,n] in a proper location */
+      u[u_loc(scf, n, n)] = un[n];
+      return;
+}
+
+/***********************************************************************
+*  The routine transform restores triangular structure of matrix U.
+*  It is a driver to the routines bg_transform and gr_transform (see
+*  comments to these routines above). */
+
+static void transform(SCF *scf, int k, double un[])
+{     switch (scf->t_opt)
+      {  case SCF_TBG:
+            bg_transform(scf, k, un);
+            break;
+         case SCF_TGR:
+            gr_transform(scf, k, un);
+            break;
+         default:
+            xassert(scf != scf);
+      }
+      return;
+}
+
+/***********************************************************************
+*  The routine estimate_rank estimates the rank of matrix C.
+*
+*  Since all transformations applied to matrix F are non-singular,
+*  and F is assumed to be well conditioned, from the main equaility
+*  F * C = U * P it follows that rank(C) = rank(U), where rank(U) is
+*  estimated as the number of non-zero diagonal elements of U. */
+
+static int estimate_rank(SCF *scf)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      double *u = scf->u;
+      int i, ii, inc, rank = 0;
+      for (i = 1, ii = u_loc(scf, i, i), inc = n_max; i <= n;
+         i++, ii += inc, inc--)
+         if (u[ii] != 0.0) rank++;
+      return rank;
+}
+
+#if _GLPSCF_DEBUG
+/***********************************************************************
+*  The routine check_error computes the maximal relative error between
+*  left- and right-hand sides of the main equality F * C = U * P. (This
+*  routine is intended only for debugging.) */
+
+static void check_error(SCF *scf, const char *func)
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+      double *c = scf->c;
+      int i, j, k;
+      double d, dmax = 0.0, s, t;
+      xassert(c != NULL);
+      for (i = 1; i <= n; i++)
+      {  for (j = 1; j <= n; j++)
+         {  /* compute element (i,j) of product F * C */
+            s = 0.0;
+            for (k = 1; k <= n; k++)
+               s += f[f_loc(scf, i, k)] * c[f_loc(scf, k, j)];
+            /* compute element (i,j) of product U * P */
+            k = p[j];
+            t = (i <= k ? u[u_loc(scf, i, k)] : 0.0);
+            /* compute the maximal relative error */
+            d = fabs(s - t) / (1.0 + fabs(t));
+            if (dmax < d) dmax = d;
+         }
+      }
+      if (dmax > 1e-8)
+         xprintf("%s: dmax = %g; relative error too large\n", func,
+            dmax);
+      return;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  scf_update_exp - update factorization on expanding C
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  int scf_update_exp(SCF *scf, const double x[], const double y[],
+*     double z);
+*
+*  DESCRIPTION
+*
+*  The routine scf_update_exp updates the factorization of matrix C on
+*  expanding it by adding a new row and column as follows:
+*
+*             ( C  x )
+*     new C = (      )
+*             ( y' z )
+*
+*  where x[1,...,n] is a new column, y[1,...,n] is a new row, and z is
+*  a new diagonal element.
+*
+*  If on entry the factorization is empty, the parameters x and y can
+*  be specified as NULL.
+*
+*  RETURNS
+*
+*  0  The factorization has been successfully updated.
+*
+*  SCF_ESING
+*     The factorization has been successfully updated, however, new
+*     matrix C is singular within working precision. Note that the new
+*     factorization remains valid.
+*
+*  SCF_ELIMIT
+*     There is not enough room to expand the factorization, because
+*     n = n_max. The factorization remains unchanged.
+*
+*  ALGORITHM
+*
+*  We can see that:
+*
+*     ( F  0 ) ( C  x )   ( FC  Fx )   ( UP  Fx )
+*     (      ) (      ) = (        ) = (        ) =
+*     ( 0  1 ) ( y' z )   ( y'   z )   ( y'   z )
+*
+*        ( U   Fx ) ( P  0 )
+*     =  (        ) (      ),
+*        ( y'P' z ) ( 0  1 )
+*
+*  therefore to keep the main equality F * C = U * P we can take:
+*
+*             ( F  0 )           ( U   Fx )           ( P  0 )
+*     new F = (      ),  new U = (        ),  new P = (      ),
+*             ( 0  1 )           ( y'P' z )           ( 0  1 )
+*
+*  and eliminate the row spike y'P' in the last row of new U to restore
+*  its upper triangular structure. */
+
+int scf_update_exp(SCF *scf, const double x[], const double y[],
+      double z)
+{     int n_max = scf->n_max;
+      int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+#if _GLPSCF_DEBUG
+      double *c = scf->c;
+#endif
+      double *un = scf->w;
+      int i, ij, in, j, k, nj, ret = 0;
+      double t;
+      /* check if the factorization can be expanded */
+      if (n == n_max)
+      {  /* there is not enough room */
+         ret = SCF_ELIMIT;
+         goto done;
+      }
+      /* increase the order of the factorization */
+      scf->n = ++n;
+      /* fill new zero column of matrix F */
+      for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
+         f[in] = 0.0;
+      /* fill new zero row of matrix F */
+      for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
+         f[nj] = 0.0;
+      /* fill new unity diagonal element of matrix F */
+      f[f_loc(scf, n, n)] = 1.0;
+      /* compute new column of matrix U, which is (old F) * x */
+      for (i = 1; i < n; i++)
+      {  /* u[i,n] := (i-th row of old F) * x */
+         t = 0.0;
+         for (j = 1, ij = f_loc(scf, i, 1); j < n; j++, ij++)
+            t += f[ij] * x[j];
+         u[u_loc(scf, i, n)] = t;
+      }
+      /* compute new (spiked) row of matrix U, which is (old P) * y */
+      for (j = 1; j < n; j++) un[j] = y[p[j]];
+      /* store new diagonal element of matrix U, which is z */
+      un[n] = z;
+      /* expand matrix P */
+      p[n] = n;
+#if _GLPSCF_DEBUG
+      /* expand matrix C */
+      /* fill its new column, which is x */
+      for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max)
+         c[in] = x[i];
+      /* fill its new row, which is y */
+      for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++)
+         c[nj] = y[j];
+      /* fill its new diagonal element, which is z */
+      c[f_loc(scf, n, n)] = z;
+#endif
+      /* restore upper triangular structure of matrix U */
+      for (k = 1; k < n; k++)
+         if (un[k] != 0.0) break;
+      transform(scf, k, un);
+      /* estimate the rank of matrices C and U */
+      scf->rank = estimate_rank(scf);
+      if (scf->rank != n) ret = SCF_ESING;
+#if _GLPSCF_DEBUG
+      /* check that the factorization is accurate enough */
+      check_error(scf, "scf_update_exp");
+#endif
+done: return ret;
+}
+
+/***********************************************************************
+*  The routine solve solves the system C * x = b.
+*
+*  From the main equation F * C = U * P it follows that:
+*
+*     C * x = b  =>  F * C * x = F * b  =>  U * P * x = F * b  =>
+*
+*     P * x = inv(U) * F * b  =>  x = P' * inv(U) * F * b.
+*
+*  On entry the array x contains right-hand side vector b. On exit this
+*  array contains solution vector x. */
+
+static void solve(SCF *scf, double x[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+      double *y = scf->w;
+      int i, j, ij;
+      double t;
+      /* y := F * b */
+      for (i = 1; i <= n; i++)
+      {  /* y[i] = (i-th row of F) * b */
+         t = 0.0;
+         for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
+            t += f[ij] * x[j];
+         y[i] = t;
+      }
+      /* y := inv(U) * y */
+      for (i = n; i >= 1; i--)
+      {  t = y[i];
+         for (j = n, ij = u_loc(scf, i, n); j > i; j--, ij--)
+            t -= u[ij] * y[j];
+         y[i] = t / u[ij];
+      }
+      /* x := P' * y */
+      for (i = 1; i <= n; i++) x[p[i]] = y[i];
+      return;
+}
+
+/***********************************************************************
+*  The routine tsolve solves the transposed system C' * x = b.
+*
+*  From the main equation F * C = U * P it follows that:
+*
+*     C' * F' = P' * U',
+*
+*  therefore:
+*
+*     C' * x = b  =>  C' * F' * inv(F') * x = b  =>
+*
+*     P' * U' * inv(F') * x = b  =>  U' * inv(F') * x = P * b  =>
+*
+*     inv(F') * x = inv(U') * P * b  =>  x = F' * inv(U') * P * b.
+*
+*  On entry the array x contains right-hand side vector b. On exit this
+*  array contains solution vector x. */
+
+static void tsolve(SCF *scf, double x[])
+{     int n = scf->n;
+      double *f = scf->f;
+      double *u = scf->u;
+      int *p = scf->p;
+      double *y = scf->w;
+      int i, j, ij;
+      double t;
+      /* y := P * b */
+      for (i = 1; i <= n; i++) y[i] = x[p[i]];
+      /* y := inv(U') * y */
+      for (i = 1; i <= n; i++)
+      {  /* compute y[i] */
+         ij = u_loc(scf, i, i);
+         t = (y[i] /= u[ij]);
+         /* substitute y[i] in other equations */
+         for (j = i+1, ij++; j <= n; j++, ij++)
+            y[j] -= u[ij] * t;
+      }
+      /* x := F' * y (computed as linear combination of rows of F) */
+      for (j = 1; j <= n; j++) x[j] = 0.0;
+      for (i = 1; i <= n; i++)
+      {  t = y[i]; /* coefficient of linear combination */
+         for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++)
+            x[j] += f[ij] * t;
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  scf_solve_it - solve either system C * x = b or C' * x = b
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  void scf_solve_it(SCF *scf, int tr, double x[]);
+*
+*  DESCRIPTION
+*
+*  The routine scf_solve_it solves either the system C * x = b (if tr
+*  is zero) or the system C' * x = b, where C' is a matrix transposed
+*  to C (if tr is non-zero). C is assumed to be non-singular.
+*
+*  On entry the array x should contain the right-hand side vector b in
+*  locations x[1], ..., x[n], where n is the order of matrix C. On exit
+*  the array x contains the solution vector x in the same locations. */
+
+void scf_solve_it(SCF *scf, int tr, double x[])
+{     if (scf->rank < scf->n)
+         xfault("scf_solve_it: singular matrix\n");
+      if (!tr)
+         solve(scf, x);
+      else
+         tsolve(scf, x);
+      return;
+}
+
+void scf_reset_it(SCF *scf)
+{     /* reset factorization for empty matrix C */
+      scf->n = scf->rank = 0;
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  scf_delete_it - delete Schur complement factorization
+*
+*  SYNOPSIS
+*
+*  #include "glpscf.h"
+*  void scf_delete_it(SCF *scf);
+*
+*  DESCRIPTION
+*
+*  The routine scf_delete_it deletes the specified factorization and
+*  frees all the memory allocated to this object. */
+
+void scf_delete_it(SCF *scf)
+{     xfree(scf->f);
+      xfree(scf->u);
+      xfree(scf->p);
+#if _GLPSCF_DEBUG
+      xfree(scf->c);
+#endif
+      xfree(scf->w);
+      xfree(scf);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpscf.h
===================================================================
--- deps/glpk/src/glpscf.h	(revision 9)
+++ deps/glpk/src/glpscf.h	(revision 9)
@@ -0,0 +1,126 @@
+/* glpscf.h (Schur complement factorization) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPSCF_H
+#define GLPSCF_H
+
+/***********************************************************************
+*  The structure SCF defines the following factorization of a square
+*  nxn matrix C (which is the Schur complement):
+*
+*     F * C = U * P,
+*
+*  where F is a square transforming matrix, U is an upper triangular
+*  matrix, P is a permutation matrix.
+*
+*  It is assumed that matrix C is small and dense, so matrices F and U
+*  are stored in the dense format by rows as follows:
+*
+*        1         n       n_max    1         n       n_max
+*      1 * * * * * * x x x x      1 * * * * * * x x x x
+*        * * * * * * x x x x        . * * * * * x x x x
+*        * * * * * * x x x x        . . * * * * x x x x
+*        * * * * * * x x x x        . . . * * * x x x x
+*        * * * * * * x x x x        . . . . * * x x x x
+*      n * * * * * * x x x x      n . . . . . * x x x x
+*        x x x x x x x x x x        . . . . . . x x x x
+*        x x x x x x x x x x        . . . . . . . x x x
+*        x x x x x x x x x x        . . . . . . . . x x
+*  n_max x x x x x x x x x x  n_max . . . . . . . . . x
+*
+*             matrix F                   matrix U
+*
+*  where '*' are matrix elements, 'x' are reserved locations.
+*
+*  Permutation matrix P is stored in row-like format.
+*
+*  Matrix C normally is not stored.
+*
+*  REFERENCES
+*
+*  1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza-
+*     tion," SCCM, Stanford University, 2006.
+*
+*  2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer-
+*     sity, Spring 2006.
+*
+*  3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package,"
+*     ibid. */
+
+typedef struct SCF SCF;
+
+struct SCF
+{     /* Schur complement factorization */
+      int n_max;
+      /* maximal order of matrices C, F, U, P; n_max >= 1 */
+      int n;
+      /* current order of matrices C, F, U, P; n >= 0 */
+      double *f; /* double f[1+n_max*n_max]; */
+      /* matrix F stored by rows */
+      double *u; /* double u[1+n_max*(n_max+1)/2]; */
+      /* upper triangle of matrix U stored by rows */
+      int *p; /* int p[1+n_max]; */
+      /* matrix P; p[i] = j means that P[i,j] = 1 */
+      int t_opt;
+      /* type of transformation used to restore triangular structure of
+         matrix U: */
+#define SCF_TBG      1  /* Bartels-Golub elimination */
+#define SCF_TGR      2  /* Givens plane rotation */
+      int rank;
+      /* estimated rank of matrices C and U */
+      double *c; /* double c[1+n_max*n_max]; */
+      /* matrix C stored in the same format as matrix F and used only
+         for debugging; normally this array is not allocated */
+      double *w; /* double w[1+n_max]; */
+      /* working array */
+};
+
+/* return codes: */
+#define SCF_ESING    1  /* singular matrix */
+#define SCF_ELIMIT   2  /* update limit reached */
+
+#define scf_create_it _glp_scf_create_it
+SCF *scf_create_it(int n_max);
+/* create Schur complement factorization */
+
+#define scf_update_exp _glp_scf_update_exp
+int scf_update_exp(SCF *scf, const double x[], const double y[],
+      double z);
+/* update factorization on expanding C */
+
+#define scf_solve_it _glp_scf_solve_it
+void scf_solve_it(SCF *scf, int tr, double x[]);
+/* solve either system C * x = b or C' * x = b */
+
+#define scf_reset_it _glp_scf_reset_it
+void scf_reset_it(SCF *scf);
+/* reset factorization for empty matrix C */
+
+#define scf_delete_it _glp_scf_delete_it
+void scf_delete_it(SCF *scf);
+/* delete Schur complement factorization */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpscl.c
===================================================================
--- deps/glpk/src/glpscl.c	(revision 9)
+++ deps/glpk/src/glpscl.c	(revision 9)
@@ -0,0 +1,476 @@
+/* glpscl.c (problem scaling routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpapi.h"
+
+/***********************************************************************
+*  min_row_aij - determine minimal |a[i,j]| in i-th row
+*
+*  This routine returns minimal magnitude of (non-zero) constraint
+*  coefficients in i-th row of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If i-th row of the matrix is empty, the routine returns 1. */
+
+static double min_row_aij(glp_prob *lp, int i, int scaled)
+{     GLPAIJ *aij;
+      double min_aij, temp;
+      xassert(1 <= i && i <= lp->m);
+      min_aij = 1.0;
+      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->r_prev == NULL || min_aij > temp)
+            min_aij = temp;
+      }
+      return min_aij;
+}
+
+/***********************************************************************
+*  max_row_aij - determine maximal |a[i,j]| in i-th row
+*
+*  This routine returns maximal magnitude of (non-zero) constraint
+*  coefficients in i-th row of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If i-th row of the matrix is empty, the routine returns 1. */
+
+static double max_row_aij(glp_prob *lp, int i, int scaled)
+{     GLPAIJ *aij;
+      double max_aij, temp;
+      xassert(1 <= i && i <= lp->m);
+      max_aij = 1.0;
+      for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->r_prev == NULL || max_aij < temp)
+            max_aij = temp;
+      }
+      return max_aij;
+}
+
+/***********************************************************************
+*  min_col_aij - determine minimal |a[i,j]| in j-th column
+*
+*  This routine returns minimal magnitude of (non-zero) constraint
+*  coefficients in j-th column of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If j-th column of the matrix is empty, the routine returns 1. */
+
+static double min_col_aij(glp_prob *lp, int j, int scaled)
+{     GLPAIJ *aij;
+      double min_aij, temp;
+      xassert(1 <= j && j <= lp->n);
+      min_aij = 1.0;
+      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->c_prev == NULL || min_aij > temp)
+            min_aij = temp;
+      }
+      return min_aij;
+}
+
+/***********************************************************************
+*  max_col_aij - determine maximal |a[i,j]| in j-th column
+*
+*  This routine returns maximal magnitude of (non-zero) constraint
+*  coefficients in j-th column of the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If j-th column of the matrix is empty, the routine returns 1. */
+
+static double max_col_aij(glp_prob *lp, int j, int scaled)
+{     GLPAIJ *aij;
+      double max_aij, temp;
+      xassert(1 <= j && j <= lp->n);
+      max_aij = 1.0;
+      for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+      {  temp = fabs(aij->val);
+         if (scaled) temp *= (aij->row->rii * aij->col->sjj);
+         if (aij->c_prev == NULL || max_aij < temp)
+            max_aij = temp;
+      }
+      return max_aij;
+}
+
+/***********************************************************************
+*  min_mat_aij - determine minimal |a[i,j]| in constraint matrix
+*
+*  This routine returns minimal magnitude of (non-zero) constraint
+*  coefficients in the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If the matrix is empty, the routine returns 1. */
+
+static double min_mat_aij(glp_prob *lp, int scaled)
+{     int i;
+      double min_aij, temp;
+      min_aij = 1.0;
+      for (i = 1; i <= lp->m; i++)
+      {  temp = min_row_aij(lp, i, scaled);
+         if (i == 1 || min_aij > temp)
+            min_aij = temp;
+      }
+      return min_aij;
+}
+
+/***********************************************************************
+*  max_mat_aij - determine maximal |a[i,j]| in constraint matrix
+*
+*  This routine returns maximal magnitude of (non-zero) constraint
+*  coefficients in the constraint matrix.
+*
+*  If the parameter scaled is zero, the original constraint matrix A is
+*  assumed. Otherwise, the scaled constraint matrix R*A*S is assumed.
+*
+*  If the matrix is empty, the routine returns 1. */
+
+static double max_mat_aij(glp_prob *lp, int scaled)
+{     int i;
+      double max_aij, temp;
+      max_aij = 1.0;
+      for (i = 1; i <= lp->m; i++)
+      {  temp = max_row_aij(lp, i, scaled);
+         if (i == 1 || max_aij < temp)
+            max_aij = temp;
+      }
+      return max_aij;
+}
+
+/***********************************************************************
+*  eq_scaling - perform equilibration scaling
+*
+*  This routine performs equilibration scaling of rows and columns of
+*  the constraint matrix.
+*
+*  If the parameter flag is zero, the routine scales rows at first and
+*  then columns. Otherwise, the routine scales columns and then rows.
+*
+*  Rows are scaled as follows:
+*
+*                         n
+*     a'[i,j] = a[i,j] / max |a[i,j]|,  i = 1,...,m.
+*                        j=1
+*
+*  This makes the infinity (maximum) norm of each row of the matrix
+*  equal to 1.
+*
+*  Columns are scaled as follows:
+*
+*                         m
+*     a'[i,j] = a[i,j] / max |a[i,j]|,  j = 1,...,n.
+*                        i=1
+*
+*  This makes the infinity (maximum) norm of each column of the matrix
+*  equal to 1. */
+
+static void eq_scaling(glp_prob *lp, int flag)
+{     int i, j, pass;
+      double temp;
+      xassert(flag == 0 || flag == 1);
+      for (pass = 0; pass <= 1; pass++)
+      {  if (pass == flag)
+         {  /* scale rows */
+            for (i = 1; i <= lp->m; i++)
+            {  temp = max_row_aij(lp, i, 1);
+               glp_set_rii(lp, i, glp_get_rii(lp, i) / temp);
+            }
+         }
+         else
+         {  /* scale columns */
+            for (j = 1; j <= lp->n; j++)
+            {  temp = max_col_aij(lp, j, 1);
+               glp_set_sjj(lp, j, glp_get_sjj(lp, j) / temp);
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  gm_scaling - perform geometric mean scaling
+*
+*  This routine performs geometric mean scaling of rows and columns of
+*  the constraint matrix.
+*
+*  If the parameter flag is zero, the routine scales rows at first and
+*  then columns. Otherwise, the routine scales columns and then rows.
+*
+*  Rows are scaled as follows:
+*
+*     a'[i,j] = a[i,j] / sqrt(alfa[i] * beta[i]),  i = 1,...,m,
+*
+*  where:
+*                n                        n
+*     alfa[i] = min |a[i,j]|,  beta[i] = max |a[i,j]|.
+*               j=1                      j=1
+*
+*  This allows decreasing the ratio beta[i] / alfa[i] for each row of
+*  the matrix.
+*
+*  Columns are scaled as follows:
+*
+*     a'[i,j] = a[i,j] / sqrt(alfa[j] * beta[j]),  j = 1,...,n,
+*
+*  where:
+*                m                        m
+*     alfa[j] = min |a[i,j]|,  beta[j] = max |a[i,j]|.
+*               i=1                      i=1
+*
+*  This allows decreasing the ratio beta[j] / alfa[j] for each column
+*  of the matrix. */
+
+static void gm_scaling(glp_prob *lp, int flag)
+{     int i, j, pass;
+      double temp;
+      xassert(flag == 0 || flag == 1);
+      for (pass = 0; pass <= 1; pass++)
+      {  if (pass == flag)
+         {  /* scale rows */
+            for (i = 1; i <= lp->m; i++)
+            {  temp = min_row_aij(lp, i, 1) * max_row_aij(lp, i, 1);
+               glp_set_rii(lp, i, glp_get_rii(lp, i) / sqrt(temp));
+            }
+         }
+         else
+         {  /* scale columns */
+            for (j = 1; j <= lp->n; j++)
+            {  temp = min_col_aij(lp, j, 1) * max_col_aij(lp, j, 1);
+               glp_set_sjj(lp, j, glp_get_sjj(lp, j) / sqrt(temp));
+            }
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  max_row_ratio - determine worst scaling "quality" for rows
+*
+*  This routine returns the worst scaling "quality" for rows of the
+*  currently scaled constraint matrix:
+*
+*              m
+*     ratio = max ratio[i],
+*             i=1
+*  where:
+*                 n              n
+*     ratio[i] = max |a[i,j]| / min |a[i,j]|,  1 <= i <= m,
+*                j=1            j=1
+*
+*  is the scaling "quality" of i-th row. */
+
+static double max_row_ratio(glp_prob *lp)
+{     int i;
+      double ratio, temp;
+      ratio = 1.0;
+      for (i = 1; i <= lp->m; i++)
+      {  temp = max_row_aij(lp, i, 1) / min_row_aij(lp, i, 1);
+         if (i == 1 || ratio < temp) ratio = temp;
+      }
+      return ratio;
+}
+
+/***********************************************************************
+*  max_col_ratio - determine worst scaling "quality" for columns
+*
+*  This routine returns the worst scaling "quality" for columns of the
+*  currently scaled constraint matrix:
+*
+*              n
+*     ratio = max ratio[j],
+*             j=1
+*  where:
+*                 m              m
+*     ratio[j] = max |a[i,j]| / min |a[i,j]|,  1 <= j <= n,
+*                i=1            i=1
+*
+*  is the scaling "quality" of j-th column. */
+
+static double max_col_ratio(glp_prob *lp)
+{     int j;
+      double ratio, temp;
+      ratio = 1.0;
+      for (j = 1; j <= lp->n; j++)
+      {  temp = max_col_aij(lp, j, 1) / min_col_aij(lp, j, 1);
+         if (j == 1 || ratio < temp) ratio = temp;
+      }
+      return ratio;
+}
+
+/***********************************************************************
+*  gm_iterate - perform iterative geometric mean scaling
+*
+*  This routine performs iterative geometric mean scaling of rows and
+*  columns of the constraint matrix.
+*
+*  The parameter it_max specifies the maximal number of iterations.
+*  Recommended value of it_max is 15.
+*
+*  The parameter tau specifies a minimal improvement of the scaling
+*  "quality" on each iteration, 0 < tau < 1. It means than the scaling
+*  process continues while the following condition is satisfied:
+*
+*     ratio[k] <= tau * ratio[k-1],
+*
+*  where ratio = max |a[i,j]| / min |a[i,j]| is the scaling "quality"
+*  to be minimized, k is the iteration number. Recommended value of tau
+*  is 0.90. */
+
+static void gm_iterate(glp_prob *lp, int it_max, double tau)
+{     int k, flag;
+      double ratio = 0.0, r_old;
+      /* if the scaling "quality" for rows is better than for columns,
+         the rows are scaled first; otherwise, the columns are scaled
+         first */
+      flag = (max_row_ratio(lp) > max_col_ratio(lp));
+      for (k = 1; k <= it_max; k++)
+      {  /* save the scaling "quality" from previous iteration */
+         r_old = ratio;
+         /* determine the current scaling "quality" */
+         ratio = max_mat_aij(lp, 1) / min_mat_aij(lp, 1);
+#if 0
+         xprintf("k = %d; ratio = %g\n", k, ratio);
+#endif
+         /* if improvement is not enough, terminate scaling */
+         if (k > 1 && ratio > tau * r_old) break;
+         /* otherwise, perform another iteration */
+         gm_scaling(lp, flag);
+      }
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  scale_prob - scale problem data
+*
+*  SYNOPSIS
+*
+*  #include "glpscl.h"
+*  void scale_prob(glp_prob *lp, int flags);
+*
+*  DESCRIPTION
+*
+*  The routine scale_prob performs automatic scaling of problem data
+*  for the specified problem object. */
+
+static void scale_prob(glp_prob *lp, int flags)
+{     static const char *fmt =
+         "%s: min|aij| = %10.3e  max|aij| = %10.3e  ratio = %10.3e\n";
+      double min_aij, max_aij, ratio;
+      xprintf("Scaling...\n");
+      /* cancel the current scaling effect */
+      glp_unscale_prob(lp);
+      /* report original scaling "quality" */
+      min_aij = min_mat_aij(lp, 1);
+      max_aij = max_mat_aij(lp, 1);
+      ratio = max_aij / min_aij;
+      xprintf(fmt, " A", min_aij, max_aij, ratio);
+      /* check if the problem is well scaled */
+      if (min_aij >= 0.10 && max_aij <= 10.0)
+      {  xprintf("Problem data seem to be well scaled\n");
+         /* skip scaling, if required */
+         if (flags & GLP_SF_SKIP) goto done;
+      }
+      /* perform iterative geometric mean scaling, if required */
+      if (flags & GLP_SF_GM)
+      {  gm_iterate(lp, 15, 0.90);
+         min_aij = min_mat_aij(lp, 1);
+         max_aij = max_mat_aij(lp, 1);
+         ratio = max_aij / min_aij;
+         xprintf(fmt, "GM", min_aij, max_aij, ratio);
+      }
+      /* perform equilibration scaling, if required */
+      if (flags & GLP_SF_EQ)
+      {  eq_scaling(lp, max_row_ratio(lp) > max_col_ratio(lp));
+         min_aij = min_mat_aij(lp, 1);
+         max_aij = max_mat_aij(lp, 1);
+         ratio = max_aij / min_aij;
+         xprintf(fmt, "EQ", min_aij, max_aij, ratio);
+      }
+      /* round scale factors to nearest power of two, if required */
+      if (flags & GLP_SF_2N)
+      {  int i, j;
+         for (i = 1; i <= lp->m; i++)
+            glp_set_rii(lp, i, round2n(glp_get_rii(lp, i)));
+         for (j = 1; j <= lp->n; j++)
+            glp_set_sjj(lp, j, round2n(glp_get_sjj(lp, j)));
+         min_aij = min_mat_aij(lp, 1);
+         max_aij = max_mat_aij(lp, 1);
+         ratio = max_aij / min_aij;
+         xprintf(fmt, "2N", min_aij, max_aij, ratio);
+      }
+done: return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_scale_prob - scale problem data
+*
+*  SYNOPSIS
+*
+*  void glp_scale_prob(glp_prob *lp, int flags);
+*
+*  DESCRIPTION
+*
+*  The routine glp_scale_prob performs automatic scaling of problem
+*  data for the specified problem object.
+*
+*  The parameter flags specifies scaling options used by the routine.
+*  Options can be combined with the bitwise OR operator and may be the
+*  following:
+*
+*  GLP_SF_GM      perform geometric mean scaling;
+*  GLP_SF_EQ      perform equilibration scaling;
+*  GLP_SF_2N      round scale factors to nearest power of two;
+*  GLP_SF_SKIP    skip scaling, if the problem is well scaled.
+*
+*  The parameter flags may be specified as GLP_SF_AUTO, in which case
+*  the routine chooses scaling options automatically. */
+
+void glp_scale_prob(glp_prob *lp, int flags)
+{     if (flags & ~(GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP |
+                    GLP_SF_AUTO))
+         xerror("glp_scale_prob: flags = 0x%02X; invalid scaling option"
+            "s\n", flags);
+      if (flags & GLP_SF_AUTO)
+         flags = (GLP_SF_GM | GLP_SF_EQ | GLP_SF_SKIP);
+      scale_prob(lp, flags);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpsdf.c
===================================================================
--- deps/glpk/src/glpsdf.c	(revision 9)
+++ deps/glpk/src/glpsdf.c	(revision 9)
@@ -0,0 +1,262 @@
+/* glpsdf.c (plain data file reading routines) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define GLPSDF_H
+
+#define GLP_DATA_DEFINED
+typedef struct glp_data glp_data;
+
+#include "glpapi.h"
+
+struct glp_data
+{     /* plain data file */
+      char *fname;
+      /* name of data file */
+      XFILE *fp;
+      /* stream assigned to data file */
+      void *jump; /* jmp_buf jump; */
+      /* label for go to in case of error */
+      int count;
+      /* line count */
+      int c;
+      /* current character of XEOF */
+      char item[255+1];
+      /* current data item */
+};
+
+static void next_char(glp_data *data);
+
+glp_data *glp_sdf_open_file(const char *fname)
+{     /* open plain data file */
+      glp_data *data = NULL;
+      XFILE *fp;
+      jmp_buf jump;
+      fp = xfopen(fname, "r");
+      if (fp == NULL)
+      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
+         goto done;
+      }
+      data = xmalloc(sizeof(glp_data));
+      data->fname = xmalloc(strlen(fname)+1);
+      strcpy(data->fname, fname);
+      data->fp = fp;
+      data->jump = NULL;
+      data->count = 0;
+      data->c = '\n';
+      data->item[0] = '\0';
+      /* read the very first character */
+      if (setjmp(jump))
+      {  glp_sdf_close_file(data);
+         data = NULL;
+         goto done;
+      }
+      data->jump = jump;
+      next_char(data);
+      data->jump = NULL;
+done: return data;
+}
+
+void glp_sdf_set_jump(glp_data *data, void *jump)
+{     /* set up error handling */
+      data->jump = jump;
+      return;
+}
+
+void glp_sdf_error(glp_data *data, const char *fmt, ...)
+{     /* print error message */
+      va_list arg;
+      xprintf("%s:%d: ", data->fname, data->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      if (data->jump == NULL)
+         xerror("");
+      else
+         longjmp(data->jump, 1);
+      /* no return */
+}
+
+void glp_sdf_warning(glp_data *data, const char *fmt, ...)
+{     /* print warning message */
+      va_list arg;
+      xprintf("%s:%d: warning: ", data->fname, data->count);
+      va_start(arg, fmt);
+      xvprintf(fmt, arg);
+      va_end(arg);
+      return;
+}
+
+static void next_char(glp_data *data)
+{     /* read next character */
+      int c;
+      if (data->c == XEOF)
+         glp_sdf_error(data, "unexpected end of file\n");
+      else if (data->c == '\n')
+         data->count++;
+      c = xfgetc(data->fp);
+      if (c < 0)
+      {  if (xferror(data->fp))
+            glp_sdf_error(data, "read error - %s\n", xerrmsg());
+         else if (data->c == '\n')
+            c = XEOF;
+         else
+         {  glp_sdf_warning(data, "missing final end of line\n");
+            c = '\n';
+         }
+      }
+      else if (c == '\n')
+         ;
+      else if (isspace(c))
+         c = ' ';
+      else if (iscntrl(c))
+         glp_sdf_error(data, "invalid control character 0x%02X\n", c);
+      data->c = c;
+      return;
+}
+
+static void skip_pad(glp_data *data)
+{     /* skip uninteresting characters and comments */
+loop: while (data->c == ' ' || data->c == '\n')
+         next_char(data);
+      if (data->c == '/')
+      {  next_char(data);
+         if (data->c != '*')
+            glp_sdf_error(data, "invalid use of slash\n");
+         next_char(data);
+         for (;;)
+         {  if (data->c == '*')
+            {  next_char(data);
+               if (data->c == '/')
+               {  next_char(data);
+                  break;
+               }
+            }
+            next_char(data);
+         }
+         goto loop;
+      }
+      return;
+}
+
+static void next_item(glp_data *data)
+{     /* read next item */
+      int len;
+      skip_pad(data);
+      len = 0;
+      while (!(data->c == ' ' || data->c == '\n'))
+      {  data->item[len++] = (char)data->c;
+         if (len == sizeof(data->item))
+            glp_sdf_error(data, "data item `%.31s...' too long\n",
+               data->item);
+         next_char(data);
+      }
+      data->item[len] = '\0';
+      return;
+}
+
+int glp_sdf_read_int(glp_data *data)
+{     /* read integer number */
+      int x;
+      next_item(data);
+      switch (str2int(data->item, &x))
+      {  case 0:
+            break;
+         case 1:
+            glp_sdf_error(data, "integer `%s' out of range\n",
+               data->item);
+         case 2:
+            glp_sdf_error(data, "cannot convert `%s' to integer\n",
+               data->item);
+         default:
+            xassert(data != data);
+      }
+      return x;
+}
+
+double glp_sdf_read_num(glp_data *data)
+{     /* read floating-point number */
+      double x;
+      next_item(data);
+      switch (str2num(data->item, &x))
+      {  case 0:
+            break;
+         case 1:
+            glp_sdf_error(data, "number `%s' out of range\n",
+               data->item);
+         case 2:
+            glp_sdf_error(data, "cannot convert `%s' to number\n",
+               data->item);
+         default:
+            xassert(data != data);
+      }
+      return x;
+}
+
+const char *glp_sdf_read_item(glp_data *data)
+{     /* read data item */
+      next_item(data);
+      return data->item;
+}
+
+const char *glp_sdf_read_text(glp_data *data)
+{     /* read text until end of line */
+      int c, len = 0;
+      for (;;)
+      {  c = data->c;
+         next_char(data);
+         if (c == ' ')
+         {  /* ignore initial spaces */
+            if (len == 0) continue;
+            /* and multiple ones */
+            if (data->item[len-1] == ' ') continue;
+         }
+         else if (c == '\n')
+         {  /* remove trailing space */
+            if (len > 0 && data->item[len-1] == ' ') len--;
+            /* and stop reading */
+            break;
+         }
+         /* add current character to the buffer */
+         data->item[len++] = (char)c;
+         if (len == sizeof(data->item))
+            glp_sdf_error(data, "line too long\n", data->item);
+      }
+      data->item[len] = '\0';
+      return data->item;
+}
+
+int glp_sdf_line(glp_data *data)
+{     /* determine current line number */
+      return data->count;
+}
+
+void glp_sdf_close_file(glp_data *data)
+{     /* close plain data file */
+      xfclose(data->fp);
+      xfree(data->fname);
+      xfree(data);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpspm.c
===================================================================
--- deps/glpk/src/glpspm.c	(revision 9)
+++ deps/glpk/src/glpspm.c	(revision 9)
@@ -0,0 +1,846 @@
+/* glpspm.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glphbm.h"
+#include "glprgr.h"
+#include "glpspm.h"
+
+/***********************************************************************
+*  NAME
+*
+*  spm_create_mat - create general sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_create_mat(int m, int n);
+*
+*  DESCRIPTION
+*
+*  The routine spm_create_mat creates a general sparse matrix having
+*  m rows and n columns. Being created the matrix is zero (empty), i.e.
+*  has no elements.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the matrix created. */
+
+SPM *spm_create_mat(int m, int n)
+{     SPM *A;
+      xassert(0 <= m && m < INT_MAX);
+      xassert(0 <= n && n < INT_MAX);
+      A = xmalloc(sizeof(SPM));
+      A->m = m;
+      A->n = n;
+      if (m == 0 || n == 0)
+      {  A->pool = NULL;
+         A->row = NULL;
+         A->col = NULL;
+      }
+      else
+      {  int i, j;
+         A->pool = dmp_create_pool();
+         A->row = xcalloc(1+m, sizeof(SPME *));
+         for (i = 1; i <= m; i++) A->row[i] = NULL;
+         A->col = xcalloc(1+n, sizeof(SPME *));
+         for (j = 1; j <= n; j++) A->col[j] = NULL;
+      }
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_new_elem - add new element to sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPME *spm_new_elem(SPM *A, int i, int j, double val);
+*
+*  DESCRIPTION
+*
+*  The routine spm_new_elem adds a new element to the specified sparse
+*  matrix. Parameters i, j, and val specify the row number, the column
+*  number, and a numerical value of the element, respectively.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the new element added. */
+
+SPME *spm_new_elem(SPM *A, int i, int j, double val)
+{     SPME *e;
+      xassert(1 <= i && i <= A->m);
+      xassert(1 <= j && j <= A->n);
+      e = dmp_get_atom(A->pool, sizeof(SPME));
+      e->i = i;
+      e->j = j;
+      e->val = val;
+      e->r_prev = NULL;
+      e->r_next = A->row[i];
+      if (e->r_next != NULL) e->r_next->r_prev = e;
+      e->c_prev = NULL;
+      e->c_next = A->col[j];
+      if (e->c_next != NULL) e->c_next->c_prev = e;
+      A->row[i] = A->col[j] = e;
+      return e;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_delete_mat - delete general sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  void spm_delete_mat(SPM *A);
+*
+*  DESCRIPTION
+*
+*  The routine deletes the specified general sparse matrix freeing all
+*  the memory allocated to this object. */
+
+void spm_delete_mat(SPM *A)
+{     /* delete sparse matrix */
+      if (A->pool != NULL) dmp_delete_pool(A->pool);
+      if (A->row != NULL) xfree(A->row);
+      if (A->col != NULL) xfree(A->col);
+      xfree(A);
+      return;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_test_mat_e - create test sparse matrix of E(n,c) class
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_test_mat_e(int n, int c);
+*
+*  DESCRIPTION
+*
+*  The routine spm_test_mat_e creates a test sparse matrix of E(n,c)
+*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
+*  Methods for Sparse Matrices. Springer-Verlag, 1983.
+*
+*  Matrix of E(n,c) class is a symmetric positive definite matrix of
+*  the order n. It has the number 4 on its main diagonal and the number
+*  -1 on its four co-diagonals, two of which are neighbour to the main
+*  diagonal and two others are shifted from the main diagonal on the
+*  distance c.
+*
+*  It is necessary that n >= 3 and 2 <= c <= n-1.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the matrix created. */
+
+SPM *spm_test_mat_e(int n, int c)
+{     SPM *A;
+      int i;
+      xassert(n >= 3 && 2 <= c && c <= n-1);
+      A = spm_create_mat(n, n);
+      for (i = 1; i <= n; i++)
+         spm_new_elem(A, i, i, 4.0);
+      for (i = 1; i <= n-1; i++)
+      {  spm_new_elem(A, i, i+1, -1.0);
+         spm_new_elem(A, i+1, i, -1.0);
+      }
+      for (i = 1; i <= n-c; i++)
+      {  spm_new_elem(A, i, i+c, -1.0);
+         spm_new_elem(A, i+c, i, -1.0);
+      }
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_test_mat_d - create test sparse matrix of D(n,c) class
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_test_mat_d(int n, int c);
+*
+*  DESCRIPTION
+*
+*  The routine spm_test_mat_d creates a test sparse matrix of D(n,c)
+*  class as described in the book: Ole 0sterby, Zahari Zlatev. Direct
+*  Methods for Sparse Matrices. Springer-Verlag, 1983.
+*
+*  Matrix of D(n,c) class is a non-singular matrix of the order n. It
+*  has unity main diagonal, three co-diagonals above the main diagonal
+*  on the distance c, which are cyclically continued below the main
+*  diagonal, and a triangle block of the size 10x10 in the upper right
+*  corner.
+*
+*  It is necessary that n >= 14 and 1 <= c <= n-13.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the matrix created. */
+
+SPM *spm_test_mat_d(int n, int c)
+{     SPM *A;
+      int i, j;
+      xassert(n >= 14 && 1 <= c && c <= n-13);
+      A = spm_create_mat(n, n);
+      for (i = 1; i <= n; i++)
+         spm_new_elem(A, i, i, 1.0);
+      for (i = 1; i <= n-c; i++)
+         spm_new_elem(A, i, i+c, (double)(i+1));
+      for (i = n-c+1; i <= n; i++)
+         spm_new_elem(A, i, i-n+c, (double)(i+1));
+      for (i = 1; i <= n-c-1; i++)
+         spm_new_elem(A, i, i+c+1, (double)(-i));
+      for (i = n-c; i <= n; i++)
+         spm_new_elem(A, i, i-n+c+1, (double)(-i));
+      for (i = 1; i <= n-c-2; i++)
+         spm_new_elem(A, i, i+c+2, 16.0);
+      for (i = n-c-1; i <= n; i++)
+         spm_new_elem(A, i, i-n+c+2, 16.0);
+      for (j = 1; j <= 10; j++)
+         for (i = 1; i <= 11-j; i++)
+            spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j);
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_show_mat - write sparse matrix pattern in BMP file format
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_show_mat(const SPM *A, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine spm_show_mat writes pattern of the specified sparse
+*  matrix in uncompressed BMP file format (Windows bitmap) to a binary
+*  file whose name is specified by the character string fname.
+*
+*  Each pixel corresponds to one matrix element. The pixel colors have
+*  the following meaning:
+*
+*  Black    structurally zero element
+*  White    positive element
+*  Cyan     negative element
+*  Green    zero element
+*  Red      duplicate element
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns zero. Otherwise, it prints
+*  an appropriate error message and returns non-zero. */
+
+int spm_show_mat(const SPM *A, const char *fname)
+{     int m = A->m;
+      int n = A->n;
+      int i, j, k, ret;
+      char *map;
+      xprintf("spm_show_mat: writing matrix pattern to `%s'...\n",
+         fname);
+      xassert(1 <= m && m <= 32767);
+      xassert(1 <= n && n <= 32767);
+      map = xmalloc(m * n);
+      memset(map, 0x08, m * n);
+      for (i = 1; i <= m; i++)
+      {  SPME *e;
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  j = e->j;
+            xassert(1 <= j && j <= n);
+            k = n * (i - 1) + (j - 1);
+            if (map[k] != 0x08)
+               map[k] = 0x0C;
+            else if (e->val > 0.0)
+               map[k] = 0x0F;
+            else if (e->val < 0.0)
+               map[k] = 0x0B;
+            else
+               map[k] = 0x0A;
+         }
+      }
+      ret = rgr_write_bmp16(fname, m, n, map);
+      xfree(map);
+      return ret;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_read_hbm - read sparse matrix in Harwell-Boeing format
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_read_hbm(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing
+*  format from a text file whose name is the character string fname.
+*
+*  Detailed description of the Harwell-Boeing format recognised by this
+*  routine can be found in the following report:
+*
+*  I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing
+*  Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992.
+*
+*  NOTE
+*
+*  The routine spm_read_hbm reads the matrix "as is", due to which zero
+*  and/or duplicate elements can appear in the matrix.
+*
+*  RETURNS
+*
+*  If no error occured, the routine returns a pointer to the matrix
+*  created. Otherwise, the routine prints an appropriate error message
+*  and returns NULL. */
+
+SPM *spm_read_hbm(const char *fname)
+{     SPM *A = NULL;
+      HBM *hbm;
+      int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind;
+      double val, *values;
+      char *mxtype;
+      hbm = hbm_read_mat(fname);
+      if (hbm == NULL)
+      {  xprintf("spm_read_hbm: unable to read matrix\n");
+         goto fini;
+      }
+      mxtype = hbm->mxtype;
+      nrow = hbm->nrow;
+      ncol = hbm->ncol;
+      nnzero = hbm->nnzero;
+      colptr = hbm->colptr;
+      rowind = hbm->rowind;
+      values = hbm->values;
+      if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 ||
+            strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 ||
+            strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0))
+      {  xprintf("spm_read_hbm: matrix type `%s' not supported\n",
+            mxtype);
+         goto fini;
+      }
+      A = spm_create_mat(nrow, ncol);
+      if (mxtype[1] == 'S' || mxtype[1] == 'U')
+         xassert(nrow == ncol);
+      for (j = 1; j <= ncol; j++)
+      {  beg = colptr[j];
+         end = colptr[j+1];
+         xassert(1 <= beg && beg <= end && end <= nnzero + 1);
+         for (ptr = beg; ptr < end; ptr++)
+         {  i = rowind[ptr];
+            xassert(1 <= i && i <= nrow);
+            if (mxtype[0] == 'R')
+               val = values[ptr];
+            else
+               val = 1.0;
+            spm_new_elem(A, i, j, val);
+            if (mxtype[1] == 'S' && i != j)
+               spm_new_elem(A, j, i, val);
+         }
+      }
+fini: if (hbm != NULL) hbm_free_mat(hbm);
+      return A;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_count_nnz - determine number of non-zeros in sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_count_nnz(const SPM *A);
+*
+*  RETURNS
+*
+*  The routine spm_count_nnz returns the number of structural non-zero
+*  elements in the specified sparse matrix. */
+
+int spm_count_nnz(const SPM *A)
+{     SPME *e;
+      int i, nnz = 0;
+      for (i = 1; i <= A->m; i++)
+         for (e = A->row[i]; e != NULL; e = e->r_next) nnz++;
+      return nnz;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_drop_zeros - remove zero elements from sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_drop_zeros(SPM *A, double eps);
+*
+*  DESCRIPTION
+*
+*  The routine spm_drop_zeros removes all elements from the specified
+*  sparse matrix, whose absolute value is less than eps.
+*
+*  If the parameter eps is 0, only zero elements are removed from the
+*  matrix.
+*
+*  RETURNS
+*
+*  The routine returns the number of elements removed. */
+
+int spm_drop_zeros(SPM *A, double eps)
+{     SPME *e, *next;
+      int i, count = 0;
+      for (i = 1; i <= A->m; i++)
+      {  for (e = A->row[i]; e != NULL; e = next)
+         {  next = e->r_next;
+            if (e->val == 0.0 || fabs(e->val) < eps)
+            {  /* remove element from the row list */
+               if (e->r_prev == NULL)
+                  A->row[e->i] = e->r_next;
+               else
+                  e->r_prev->r_next = e->r_next;
+               if (e->r_next == NULL)
+                  ;
+               else
+                  e->r_next->r_prev = e->r_prev;
+               /* remove element from the column list */
+               if (e->c_prev == NULL)
+                  A->col[e->j] = e->c_next;
+               else
+                  e->c_prev->c_next = e->c_next;
+               if (e->c_next == NULL)
+                  ;
+               else
+                  e->c_next->c_prev = e->c_prev;
+               /* return element to the memory pool */
+               dmp_free_atom(A->pool, e, sizeof(SPME));
+               count++;
+            }
+         }
+      }
+      return count;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  spm_read_mat - read sparse matrix from text file
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_read_mat(const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine reads a sparse matrix from a text file whose name is
+*  specified by the parameter fname.
+*
+*  For the file format see description of the routine spm_write_mat.
+*
+*  RETURNS
+*
+*  On success the routine returns a pointer to the matrix created,
+*  otherwise NULL. */
+
+#if 1
+SPM *spm_read_mat(const char *fname)
+{     xassert(fname != fname);
+      return NULL;
+}
+#else
+SPM *spm_read_mat(const char *fname)
+{     SPM *A = NULL;
+      PDS *pds;
+      jmp_buf jump;
+      int i, j, k, m, n, nnz, fail = 0;
+      double val;
+      xprintf("spm_read_mat: reading matrix from `%s'...\n", fname);
+      pds = pds_open_file(fname);
+      if (pds == NULL)
+      {  xprintf("spm_read_mat: unable to open `%s' - %s\n", fname,
+            strerror(errno));
+         fail = 1;
+         goto done;
+      }
+      if (setjmp(jump))
+      {  fail = 1;
+         goto done;
+      }
+      pds_set_jump(pds, jump);
+      /* number of rows, number of columns, number of non-zeros */
+      m = pds_scan_int(pds);
+      if (m < 0)
+         pds_error(pds, "invalid number of rows\n");
+      n = pds_scan_int(pds);
+      if (n < 0)
+         pds_error(pds, "invalid number of columns\n");
+      nnz = pds_scan_int(pds);
+      if (nnz < 0)
+         pds_error(pds, "invalid number of non-zeros\n");
+      /* create matrix */
+      xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n",
+         m, n, nnz);
+      A = spm_create_mat(m, n);
+      /* read matrix elements */
+      for (k = 1; k <= nnz; k++)
+      {  /* row index, column index, element value */
+         i = pds_scan_int(pds);
+         if (!(1 <= i && i <= m))
+            pds_error(pds, "row index out of range\n");
+         j = pds_scan_int(pds);
+         if (!(1 <= j && j <= n))
+            pds_error(pds, "column index out of range\n");
+         val = pds_scan_num(pds);
+         /* add new element to the matrix */
+         spm_new_elem(A, i, j, val);
+      }
+      xprintf("spm_read_mat: %d lines were read\n", pds->count);
+done: if (pds != NULL) pds_close_file(pds);
+      if (fail && A != NULL) spm_delete_mat(A), A = NULL;
+      return A;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  spm_write_mat - write sparse matrix to text file
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  int spm_write_mat(const SPM *A, const char *fname);
+*
+*  DESCRIPTION
+*
+*  The routine spm_write_mat writes the specified sparse matrix to a
+*  text file whose name is specified by the parameter fname. This file
+*  can be read back with the routine spm_read_mat.
+*
+*  RETURNS
+*
+*  On success the routine returns zero, otherwise non-zero.
+*
+*  FILE FORMAT
+*
+*  The file created by the routine spm_write_mat is a plain text file,
+*  which contains the following information:
+*
+*     m n nnz
+*     row[1] col[1] val[1]
+*     row[2] col[2] val[2]
+*     . . .
+*     row[nnz] col[nnz] val[nnz]
+*
+*  where:
+*  m is the number of rows;
+*  n is the number of columns;
+*  nnz is the number of non-zeros;
+*  row[k], k = 1,...,nnz, are row indices;
+*  col[k], k = 1,...,nnz, are column indices;
+*  val[k], k = 1,...,nnz, are element values. */
+
+#if 1
+int spm_write_mat(const SPM *A, const char *fname)
+{     xassert(A != A);
+      xassert(fname != fname);
+      return 0;
+}
+#else
+int spm_write_mat(const SPM *A, const char *fname)
+{     FILE *fp;
+      int i, nnz, ret = 0;
+      xprintf("spm_write_mat: writing matrix to `%s'...\n", fname);
+      fp = fopen(fname, "w");
+      if (fp == NULL)
+      {  xprintf("spm_write_mat: unable to create `%s' - %s\n", fname,
+            strerror(errno));
+         ret = 1;
+         goto done;
+      }
+      /* number of rows, number of columns, number of non-zeros */
+      nnz = spm_count_nnz(A);
+      fprintf(fp, "%d %d %d\n", A->m, A->n, nnz);
+      /* walk through rows of the matrix */
+      for (i = 1; i <= A->m; i++)
+      {  SPME *e;
+         /* walk through elements of i-th row */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  /* row index, column index, element value */
+            fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val);
+         }
+      }
+      fflush(fp);
+      if (ferror(fp))
+      {  xprintf("spm_write_mat: writing error on `%s' - %s\n", fname,
+            strerror(errno));
+         ret = 1;
+         goto done;
+      }
+      xprintf("spm_write_mat: %d lines were written\n", 1 + nnz);
+done: if (fp != NULL) fclose(fp);
+      return ret;
+}
+#endif
+
+/***********************************************************************
+*  NAME
+*
+*  spm_transpose - transpose sparse matrix
+*
+*  SYNOPSIS
+*
+*  #include "glpspm.h"
+*  SPM *spm_transpose(const SPM *A);
+*
+*  RETURNS
+*
+*  The routine computes and returns sparse matrix B, which is a matrix
+*  transposed to sparse matrix A. */
+
+SPM *spm_transpose(const SPM *A)
+{     SPM *B;
+      int i;
+      B = spm_create_mat(A->n, A->m);
+      for (i = 1; i <= A->m; i++)
+      {  SPME *e;
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            spm_new_elem(B, e->j, i, e->val);
+      }
+      return B;
+}
+
+SPM *spm_add_sym(const SPM *A, const SPM *B)
+{     /* add two sparse matrices (symbolic phase) */
+      SPM *C;
+      int i, j, *flag;
+      xassert(A->m == B->m);
+      xassert(A->n == B->n);
+      /* create resultant matrix */
+      C = spm_create_mat(A->m, A->n);
+      /* allocate and clear the flag array */
+      flag = xcalloc(1+C->n, sizeof(int));
+      for (j = 1; j <= C->n; j++)
+         flag[j] = 0;
+      /* compute pattern of C = A + B */
+      for (i = 1; i <= C->m; i++)
+      {  SPME *e;
+         /* at the beginning i-th row of C is empty */
+         /* (i-th row of C) := (i-th row of C) union (i-th row of A) */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  /* (note that i-th row of A may have duplicate elements) */
+            j = e->j;
+            if (!flag[j])
+            {  spm_new_elem(C, i, j, 0.0);
+               flag[j] = 1;
+            }
+         }
+         /* (i-th row of C) := (i-th row of C) union (i-th row of B) */
+         for (e = B->row[i]; e != NULL; e = e->r_next)
+         {  /* (note that i-th row of B may have duplicate elements) */
+            j = e->j;
+            if (!flag[j])
+            {  spm_new_elem(C, i, j, 0.0);
+               flag[j] = 1;
+            }
+         }
+         /* reset the flag array */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+            flag[e->j] = 0;
+      }
+      /* check and deallocate the flag array */
+      for (j = 1; j <= C->n; j++)
+         xassert(!flag[j]);
+      xfree(flag);
+      return C;
+}
+
+void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
+      const SPM *B)
+{     /* add two sparse matrices (numeric phase) */
+      int i, j;
+      double *work;
+      /* allocate and clear the working array */
+      work = xcalloc(1+C->n, sizeof(double));
+      for (j = 1; j <= C->n; j++)
+         work[j] = 0.0;
+      /* compute matrix C = alfa * A + beta * B */
+      for (i = 1; i <= C->n; i++)
+      {  SPME *e;
+         /* work := alfa * (i-th row of A) + beta * (i-th row of B) */
+         /* (note that A and/or B may have duplicate elements) */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            work[e->j] += alfa * e->val;
+         for (e = B->row[i]; e != NULL; e = e->r_next)
+            work[e->j] += beta * e->val;
+         /* (i-th row of C) := work, work := 0 */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+         {  j = e->j;
+            e->val = work[j];
+            work[j] = 0.0;
+         }
+      }
+      /* check and deallocate the working array */
+      for (j = 1; j <= C->n; j++)
+         xassert(work[j] == 0.0);
+      xfree(work);
+      return;
+}
+
+SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B)
+{     /* add two sparse matrices (driver routine) */
+      SPM *C;
+      C = spm_add_sym(A, B);
+      spm_add_num(C, alfa, A, beta, B);
+      return C;
+}
+
+SPM *spm_mul_sym(const SPM *A, const SPM *B)
+{     /* multiply two sparse matrices (symbolic phase) */
+      int i, j, k, *flag;
+      SPM *C;
+      xassert(A->n == B->m);
+      /* create resultant matrix */
+      C = spm_create_mat(A->m, B->n);
+      /* allocate and clear the flag array */
+      flag = xcalloc(1+C->n, sizeof(int));
+      for (j = 1; j <= C->n; j++)
+         flag[j] = 0;
+      /* compute pattern of C = A * B */
+      for (i = 1; i <= C->m; i++)
+      {  SPME *e, *ee;
+         /* compute pattern of i-th row of C */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+         {  k = e->j;
+            for (ee = B->row[k]; ee != NULL; ee = ee->r_next)
+            {  j = ee->j;
+               /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */
+               if (!flag[j])
+               {  /* c[i,j] does not exist, so create it */
+                  spm_new_elem(C, i, j, 0.0);
+                  flag[j] = 1;
+               }
+            }
+         }
+         /* reset the flag array */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+            flag[e->j] = 0;
+      }
+      /* check and deallocate the flag array */
+      for (j = 1; j <= C->n; j++)
+         xassert(!flag[j]);
+      xfree(flag);
+      return C;
+}
+
+void spm_mul_num(SPM *C, const SPM *A, const SPM *B)
+{     /* multiply two sparse matrices (numeric phase) */
+      int i, j;
+      double *work;
+      /* allocate and clear the working array */
+      work = xcalloc(1+A->n, sizeof(double));
+      for (j = 1; j <= A->n; j++)
+         work[j] = 0.0;
+      /* compute matrix C = A * B */
+      for (i = 1; i <= C->m; i++)
+      {  SPME *e, *ee;
+         double temp;
+         /* work := (i-th row of A) */
+         /* (note that A may have duplicate elements) */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            work[e->j] += e->val;
+         /* compute i-th row of C */
+         for (e = C->row[i]; e != NULL; e = e->r_next)
+         {  j = e->j;
+            /* c[i,j] := work * (j-th column of B) */
+            temp = 0.0;
+            for (ee = B->col[j]; ee != NULL; ee = ee->c_next)
+               temp += work[ee->i] * ee->val;
+            e->val = temp;
+         }
+         /* reset the working array */
+         for (e = A->row[i]; e != NULL; e = e->r_next)
+            work[e->j] = 0.0;
+      }
+      /* check and deallocate the working array */
+      for (j = 1; j <= A->n; j++)
+         xassert(work[j] == 0.0);
+      xfree(work);
+      return;
+}
+
+SPM *spm_mul_mat(const SPM *A, const SPM *B)
+{     /* multiply two sparse matrices (driver routine) */
+      SPM *C;
+      C = spm_mul_sym(A, B);
+      spm_mul_num(C, A, B);
+      return C;
+}
+
+PER *spm_create_per(int n)
+{     /* create permutation matrix */
+      PER *P;
+      int k;
+      xassert(n >= 0);
+      P = xmalloc(sizeof(PER));
+      P->n = n;
+      P->row = xcalloc(1+n, sizeof(int));
+      P->col = xcalloc(1+n, sizeof(int));
+      /* initially it is identity matrix */
+      for (k = 1; k <= n; k++)
+         P->row[k] = P->col[k] = k;
+      return P;
+}
+
+void spm_check_per(PER *P)
+{     /* check permutation matrix for correctness */
+      int i, j;
+      xassert(P->n >= 0);
+      for (i = 1; i <= P->n; i++)
+      {  j = P->row[i];
+         xassert(1 <= j && j <= P->n);
+         xassert(P->col[j] == i);
+      }
+      return;
+}
+
+void spm_delete_per(PER *P)
+{     /* delete permutation matrix */
+      xfree(P->row);
+      xfree(P->col);
+      xfree(P);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpspm.h
===================================================================
--- deps/glpk/src/glpspm.h	(revision 9)
+++ deps/glpk/src/glpspm.h	(revision 9)
@@ -0,0 +1,165 @@
+/* glpspm.h (general sparse matrix) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPSPM_H
+#define GLPSPM_H
+
+#include "glpdmp.h"
+
+typedef struct SPM SPM;
+typedef struct SPME SPME;
+
+struct SPM
+{     /* general sparse matrix */
+      int m;
+      /* number of rows, m >= 0 */
+      int n;
+      /* number of columns, n >= 0 */
+      DMP *pool;
+      /* memory pool to store matrix elements */
+      SPME **row; /* SPME *row[1+m]; */
+      /* row[i], 1 <= i <= m, is a pointer to i-th row list */
+      SPME **col; /* SPME *col[1+n]; */
+      /* col[j], 1 <= j <= n, is a pointer to j-th column list */
+};
+
+struct SPME
+{     /* sparse matrix element */
+      int i;
+      /* row number */
+      int j;
+      /* column number */
+      double val;
+      /* element value */
+      SPME *r_prev;
+      /* pointer to previous element in the same row */
+      SPME *r_next;
+      /* pointer to next element in the same row */
+      SPME *c_prev;
+      /* pointer to previous element in the same column */
+      SPME *c_next;
+      /* pointer to next element in the same column */
+};
+
+typedef struct PER PER;
+
+struct PER
+{     /* permutation matrix */
+      int n;
+      /* matrix order, n >= 0 */
+      int *row; /* int row[1+n]; */
+      /* row[i] = j means p[i,j] = 1 */
+      int *col; /* int col[1+n]; */
+      /* col[j] = i means p[i,j] = 1 */
+};
+
+#define spm_create_mat _glp_spm_create_mat
+SPM *spm_create_mat(int m, int n);
+/* create general sparse matrix */
+
+#define spm_new_elem _glp_spm_new_elem
+SPME *spm_new_elem(SPM *A, int i, int j, double val);
+/* add new element to sparse matrix */
+
+#define spm_delete_mat _glp_spm_delete_mat
+void spm_delete_mat(SPM *A);
+/* delete general sparse matrix */
+
+#define spm_test_mat_e _glp_spm_test_mat_e
+SPM *spm_test_mat_e(int n, int c);
+/* create test sparse matrix of E(n,c) class */
+
+#define spm_test_mat_d _glp_spm_test_mat_d
+SPM *spm_test_mat_d(int n, int c);
+/* create test sparse matrix of D(n,c) class */
+
+#define spm_show_mat _glp_spm_show_mat
+int spm_show_mat(const SPM *A, const char *fname);
+/* write sparse matrix pattern in BMP file format */
+
+#define spm_read_hbm _glp_spm_read_hbm
+SPM *spm_read_hbm(const char *fname);
+/* read sparse matrix in Harwell-Boeing format */
+
+#define spm_count_nnz _glp_spm_count_nnz
+int spm_count_nnz(const SPM *A);
+/* determine number of non-zeros in sparse matrix */
+
+#define spm_drop_zeros _glp_spm_drop_zeros
+int spm_drop_zeros(SPM *A, double eps);
+/* remove zero elements from sparse matrix */
+
+#define spm_read_mat _glp_spm_read_mat
+SPM *spm_read_mat(const char *fname);
+/* read sparse matrix from text file */
+
+#define spm_write_mat _glp_spm_write_mat
+int spm_write_mat(const SPM *A, const char *fname);
+/* write sparse matrix to text file */
+
+#define spm_transpose _glp_spm_transpose
+SPM *spm_transpose(const SPM *A);
+/* transpose sparse matrix */
+
+#define spm_add_sym _glp_spm_add_sym
+SPM *spm_add_sym(const SPM *A, const SPM *B);
+/* add two sparse matrices (symbolic phase) */
+
+#define spm_add_num _glp_spm_add_num
+void spm_add_num(SPM *C, double alfa, const SPM *A, double beta,
+      const SPM *B);
+/* add two sparse matrices (numeric phase) */
+
+#define spm_add_mat _glp_spm_add_mat
+SPM *spm_add_mat(double alfa, const SPM *A, double beta,
+      const SPM *B);
+/* add two sparse matrices (driver routine) */
+
+#define spm_mul_sym _glp_spm_mul_sym
+SPM *spm_mul_sym(const SPM *A, const SPM *B);
+/* multiply two sparse matrices (symbolic phase) */
+
+#define spm_mul_num _glp_spm_mul_num
+void spm_mul_num(SPM *C, const SPM *A, const SPM *B);
+/* multiply two sparse matrices (numeric phase) */
+
+#define spm_mul_mat _glp_spm_mul_mat
+SPM *spm_mul_mat(const SPM *A, const SPM *B);
+/* multiply two sparse matrices (driver routine) */
+
+#define spm_create_per _glp_spm_create_per
+PER *spm_create_per(int n);
+/* create permutation matrix */
+
+#define spm_check_per _glp_spm_check_per
+void spm_check_per(PER *P);
+/* check permutation matrix for correctness */
+
+#define spm_delete_per _glp_spm_delete_per
+void spm_delete_per(PER *P);
+/* delete permutation matrix */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpspx.h
===================================================================
--- deps/glpk/src/glpspx.h	(revision 9)
+++ deps/glpk/src/glpspx.h	(revision 9)
@@ -0,0 +1,40 @@
+/* glpspx.h (core simplex solvers) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPSPX_H
+#define GLPSPX_H
+
+#include "glpapi.h"
+
+#define spx_primal _glp_spx_primal
+int spx_primal(glp_prob *lp, const glp_smcp *parm);
+/* core LP solver based on the primal simplex method */
+
+#define spx_dual _glp_spx_dual
+int spx_dual(glp_prob *lp, const glp_smcp *parm);
+/* core LP solver based on the dual simplex method */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpspx01.c
===================================================================
--- deps/glpk/src/glpspx01.c	(revision 9)
+++ deps/glpk/src/glpspx01.c	(revision 9)
@@ -0,0 +1,2954 @@
+/* glpspx01.c (primal simplex method) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpspx.h"
+
+struct csa
+{     /* common storage area */
+      /*--------------------------------------------------------------*/
+      /* LP data */
+      int m;
+      /* number of rows (auxiliary variables), m > 0 */
+      int n;
+      /* number of columns (structural variables), n > 0 */
+      char *type; /* char type[1+m+n]; */
+      /* type[0] is not used;
+         type[k], 1 <= k <= m+n, is the type of variable x[k]:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double *lb; /* double lb[1+m+n]; */
+      /* lb[0] is not used;
+         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
+         if x[k] has no lower bound, lb[k] is zero */
+      double *ub; /* double ub[1+m+n]; */
+      /* ub[0] is not used;
+         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
+         if x[k] has no upper bound, ub[k] is zero;
+         if x[k] is of fixed type, ub[k] is the same as lb[k] */
+      double *coef; /* double coef[1+m+n]; */
+      /* coef[0] is not used;
+         coef[k], 1 <= k <= m+n, is an objective coefficient at
+         variable x[k] (note that on phase I auxiliary variables also
+         may have non-zero objective coefficients) */
+      /*--------------------------------------------------------------*/
+      /* original objective function */
+      double *obj; /* double obj[1+n]; */
+      /* obj[0] is a constant term of the original objective function;
+         obj[j], 1 <= j <= n, is an original objective coefficient at
+         structural variable x[m+j] */
+      double zeta;
+      /* factor used to scale original objective coefficients; its
+         sign defines original optimization direction: zeta > 0 means
+         minimization, zeta < 0 means maximization */
+      /*--------------------------------------------------------------*/
+      /* constraint matrix A; it has m rows and n columns and is stored
+         by columns */
+      int *A_ptr; /* int A_ptr[1+n+1]; */
+      /* A_ptr[0] is not used;
+         A_ptr[j], 1 <= j <= n, is starting position of j-th column in
+         arrays A_ind and A_val; note that A_ptr[1] is always 1;
+         A_ptr[n+1] indicates the position after the last element in
+         arrays A_ind and A_val */
+      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
+      /* row indices */
+      double *A_val; /* double A_val[A_ptr[n+1]]; */
+      /* non-zero element values */
+      /*--------------------------------------------------------------*/
+      /* basis header */
+      int *head; /* int head[1+m+n]; */
+      /* head[0] is not used;
+         head[i], 1 <= i <= m, is the ordinal number of basic variable
+         xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
+         matrix B is k-th column of matrix (I|-A);
+         head[m+j], 1 <= j <= n, is the ordinal number of non-basic
+         variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
+         column of matrix N is k-th column of matrix (I|-A) */
+      char *stat; /* char stat[1+n]; */
+      /* stat[0] is not used;
+         stat[j], 1 <= j <= n, is the status of non-basic variable
+         xN[j], which defines its active bound:
+         GLP_NL - lower bound is active
+         GLP_NU - upper bound is active
+         GLP_NF - free variable
+         GLP_NS - fixed variable */
+      /*--------------------------------------------------------------*/
+      /* matrix B is the basis matrix; it is composed from columns of
+         the augmented constraint matrix (I|-A) corresponding to basic
+         variables and stored in a factorized (invertable) form */
+      int valid;
+      /* factorization is valid only if this flag is set */
+      BFD *bfd; /* BFD bfd[1:m,1:m]; */
+      /* factorized (invertable) form of the basis matrix */
+      /*--------------------------------------------------------------*/
+      /* matrix N is a matrix composed from columns of the augmented
+         constraint matrix (I|-A) corresponding to non-basic variables
+         except fixed ones; it is stored by rows and changes every time
+         the basis changes */
+      int *N_ptr; /* int N_ptr[1+m+1]; */
+      /* N_ptr[0] is not used;
+         N_ptr[i], 1 <= i <= m, is starting position of i-th row in
+         arrays N_ind and N_val; note that N_ptr[1] is always 1;
+         N_ptr[m+1] indicates the position after the last element in
+         arrays N_ind and N_val */
+      int *N_len; /* int N_len[1+m]; */
+      /* N_len[0] is not used;
+         N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
+      int *N_ind; /* int N_ind[N_ptr[m+1]]; */
+      /* column indices */
+      double *N_val; /* double N_val[N_ptr[m+1]]; */
+      /* non-zero element values */
+      /*--------------------------------------------------------------*/
+      /* working parameters */
+      int phase;
+      /* search phase:
+         0 - not determined yet
+         1 - search for primal feasible solution
+         2 - search for optimal solution */
+      glp_long tm_beg;
+      /* time value at the beginning of the search */
+      int it_beg;
+      /* simplex iteration count at the beginning of the search */
+      int it_cnt;
+      /* simplex iteration count; it increases by one every time the
+         basis changes (including the case when a non-basic variable
+         jumps to its opposite bound) */
+      int it_dpy;
+      /* simplex iteration count at the most recent display output */
+      /*--------------------------------------------------------------*/
+      /* basic solution components */
+      double *bbar; /* double bbar[1+m]; */
+      /* bbar[0] is not used;
+         bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
+         (if xB[i] is free, its primal value is not updated) */
+      double *cbar; /* double cbar[1+n]; */
+      /* cbar[0] is not used;
+         cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
+         xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
+      /*--------------------------------------------------------------*/
+      /* the following pricing technique options may be used:
+         GLP_PT_STD - standard ("textbook") pricing;
+         GLP_PT_PSE - projected steepest edge;
+         GLP_PT_DVX - Devex pricing (not implemented yet);
+         in case of GLP_PT_STD the reference space is not used, and all
+         steepest edge coefficients are set to 1 */
+      int refct;
+      /* this count is set to an initial value when the reference space
+         is defined and decreases by one every time the basis changes;
+         once this count reaches zero, the reference space is redefined
+         again */
+      char *refsp; /* char refsp[1+m+n]; */
+      /* refsp[0] is not used;
+         refsp[k], 1 <= k <= m+n, is the flag which means that variable
+         x[k] belongs to the current reference space */
+      double *gamma; /* double gamma[1+n]; */
+      /* gamma[0] is not used;
+         gamma[j], 1 <= j <= n, is the steepest edge coefficient for
+         non-basic variable xN[j]; if xN[j] is fixed, gamma[j] is not
+         used and just set to 1 */
+      /*--------------------------------------------------------------*/
+      /* non-basic variable xN[q] chosen to enter the basis */
+      int q;
+      /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
+         if the set of eligible non-basic variables is empty and thus
+         no variable has been chosen, q is set to 0 */
+      /*--------------------------------------------------------------*/
+      /* pivot column of the simplex table corresponding to non-basic
+         variable xN[q] chosen is the following vector:
+            T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+         where B is the current basis matrix, N[q] is a column of the
+         matrix (I|-A) corresponding to xN[q] */
+      int tcol_nnz;
+      /* number of non-zero components, 0 <= nnz <= m */
+      int *tcol_ind; /* int tcol_ind[1+m]; */
+      /* tcol_ind[0] is not used;
+         tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
+      double *tcol_vec; /* double tcol_vec[1+m]; */
+      /* tcol_vec[0] is not used;
+         tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
+         of the column */
+      double tcol_max;
+      /* infinity (maximum) norm of the column (max |tcol_vec[i]|) */
+      int tcol_num;
+      /* number of significant non-zero components, which means that:
+         |tcol_vec[i]| >= eps for i in tcol_ind[1,...,num],
+         |tcol_vec[i]| <  eps for i in tcol_ind[num+1,...,nnz],
+         where eps is a pivot tolerance */
+      /*--------------------------------------------------------------*/
+      /* basic variable xB[p] chosen to leave the basis */
+      int p;
+      /* index of the basic variable xB[p] chosen, 1 <= p <= m;
+         p = 0 means that no basic variable reaches its bound;
+         p < 0 means that non-basic variable xN[q] reaches its opposite
+         bound before any basic variable */
+      int p_stat;
+      /* new status (GLP_NL, GLP_NU, or GLP_NS) to be assigned to xB[p]
+         once it has left the basis */
+      double teta;
+      /* change of non-basic variable xN[q] (see above), on which xB[p]
+         (or, if p < 0, xN[q] itself) reaches its bound */
+      /*--------------------------------------------------------------*/
+      /* pivot row of the simplex table corresponding to basic variable
+         xB[p] chosen is the following vector:
+            T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
+         where B' is a matrix transposed to the current basis matrix,
+         N' is a matrix, whose rows are columns of the matrix (I|-A)
+         corresponding to non-basic non-fixed variables */
+      int trow_nnz;
+      /* number of non-zero components, 0 <= nnz <= n */
+      int *trow_ind; /* int trow_ind[1+n]; */
+      /* trow_ind[0] is not used;
+         trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
+      double *trow_vec; /* int trow_vec[1+n]; */
+      /* trow_vec[0] is not used;
+         trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
+         of the row */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      double *work1; /* double work1[1+m]; */
+      double *work2; /* double work2[1+m]; */
+      double *work3; /* double work3[1+m]; */
+      double *work4; /* double work4[1+m]; */
+};
+
+static const double kappa = 0.10;
+
+/***********************************************************************
+*  alloc_csa - allocate common storage area
+*
+*  This routine allocates all arrays in the common storage area (CSA)
+*  and returns a pointer to the CSA. */
+
+static struct csa *alloc_csa(glp_prob *lp)
+{     struct csa *csa;
+      int m = lp->m;
+      int n = lp->n;
+      int nnz = lp->nnz;
+      csa = xmalloc(sizeof(struct csa));
+      xassert(m > 0 && n > 0);
+      csa->m = m;
+      csa->n = n;
+      csa->type = xcalloc(1+m+n, sizeof(char));
+      csa->lb = xcalloc(1+m+n, sizeof(double));
+      csa->ub = xcalloc(1+m+n, sizeof(double));
+      csa->coef = xcalloc(1+m+n, sizeof(double));
+      csa->obj = xcalloc(1+n, sizeof(double));
+      csa->A_ptr = xcalloc(1+n+1, sizeof(int));
+      csa->A_ind = xcalloc(1+nnz, sizeof(int));
+      csa->A_val = xcalloc(1+nnz, sizeof(double));
+      csa->head = xcalloc(1+m+n, sizeof(int));
+      csa->stat = xcalloc(1+n, sizeof(char));
+      csa->N_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->N_len = xcalloc(1+m, sizeof(int));
+      csa->N_ind = NULL; /* will be allocated later */
+      csa->N_val = NULL; /* will be allocated later */
+      csa->bbar = xcalloc(1+m, sizeof(double));
+      csa->cbar = xcalloc(1+n, sizeof(double));
+      csa->refsp = xcalloc(1+m+n, sizeof(char));
+      csa->gamma = xcalloc(1+n, sizeof(double));
+      csa->tcol_ind = xcalloc(1+m, sizeof(int));
+      csa->tcol_vec = xcalloc(1+m, sizeof(double));
+      csa->trow_ind = xcalloc(1+n, sizeof(int));
+      csa->trow_vec = xcalloc(1+n, sizeof(double));
+      csa->work1 = xcalloc(1+m, sizeof(double));
+      csa->work2 = xcalloc(1+m, sizeof(double));
+      csa->work3 = xcalloc(1+m, sizeof(double));
+      csa->work4 = xcalloc(1+m, sizeof(double));
+      return csa;
+}
+
+/***********************************************************************
+*  init_csa - initialize common storage area
+*
+*  This routine initializes all data structures in the common storage
+*  area (CSA). */
+
+static void alloc_N(struct csa *csa);
+static void build_N(struct csa *csa);
+
+static void init_csa(struct csa *csa, glp_prob *lp)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      double *obj = csa->obj;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int i, j, k, loc;
+      double cmax;
+      /* auxiliary variables */
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         type[i] = (char)row->type;
+         lb[i] = row->lb * row->rii;
+         ub[i] = row->ub * row->rii;
+         coef[i] = 0.0;
+      }
+      /* structural variables */
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         type[m+j] = (char)col->type;
+         lb[m+j] = col->lb / col->sjj;
+         ub[m+j] = col->ub / col->sjj;
+         coef[m+j] = col->coef * col->sjj;
+      }
+      /* original objective function */
+      obj[0] = lp->c0;
+      memcpy(&obj[1], &coef[m+1], n * sizeof(double));
+      /* factor used to scale original objective coefficients */
+      cmax = 0.0;
+      for (j = 1; j <= n; j++)
+         if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
+      if (cmax == 0.0) cmax = 1.0;
+      switch (lp->dir)
+      {  case GLP_MIN:
+            csa->zeta = + 1.0 / cmax;
+            break;
+         case GLP_MAX:
+            csa->zeta = - 1.0 / cmax;
+            break;
+         default:
+            xassert(lp != lp);
+      }
+#if 1
+      if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
+#endif
+      /* matrix A (by columns) */
+      loc = 1;
+      for (j = 1; j <= n; j++)
+      {  GLPAIJ *aij;
+         A_ptr[j] = loc;
+         for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+         {  A_ind[loc] = aij->row->i;
+            A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      A_ptr[n+1] = loc;
+      xassert(loc == lp->nnz+1);
+      /* basis header */
+      xassert(lp->valid);
+      memcpy(&head[1], &lp->head[1], m * sizeof(int));
+      k = 0;
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         if (row->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = i;
+            stat[k] = (char)row->stat;
+         }
+      }
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         if (col->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = m + j;
+            stat[k] = (char)col->stat;
+         }
+      }
+      xassert(k == n);
+      /* factorization of matrix B */
+      csa->valid = 1, lp->valid = 0;
+      csa->bfd = lp->bfd, lp->bfd = NULL;
+      /* matrix N (by rows) */
+      alloc_N(csa);
+      build_N(csa);
+      /* working parameters */
+      csa->phase = 0;
+      csa->tm_beg = xtime();
+      csa->it_beg = csa->it_cnt = lp->it_cnt;
+      csa->it_dpy = -1;
+      /* reference space and steepest edge coefficients */
+      csa->refct = 0;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (j = 1; j <= n; j++) gamma[j] = 1.0;
+      return;
+}
+
+/***********************************************************************
+*  invert_B - compute factorization of the basis matrix
+*
+*  This routine computes factorization of the current basis matrix B.
+*
+*  If the operation is successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int inv_col(void *info, int i, int ind[], double val[])
+{     /* this auxiliary routine returns row indices and numeric values
+         of non-zero elements of i-th column of the basis matrix */
+      struct csa *csa = info;
+      int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int k, len, ptr, t;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+#endif
+      k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* B[i] is k-th column of submatrix I */
+         len = 1;
+         ind[1] = k;
+         val[1] = 1.0;
+      }
+      else
+      {  /* B[i] is (k-m)-th column of submatrix (-A) */
+         ptr = A_ptr[k-m];
+         len = A_ptr[k-m+1] - ptr;
+         memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
+         memcpy(&val[1], &A_val[ptr], len * sizeof(double));
+         for (t = 1; t <= len; t++) val[t] = - val[t];
+      }
+      return len;
+}
+
+static int invert_B(struct csa *csa)
+{     int ret;
+      ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
+      csa->valid = (ret == 0);
+      return ret;
+}
+
+/***********************************************************************
+*  update_B - update factorization of the basis matrix
+*
+*  This routine replaces i-th column of the basis matrix B by k-th
+*  column of the augmented constraint matrix (I|-A) and then updates
+*  the factorization of B.
+*
+*  If the factorization has been successfully updated, the routine
+*  returns zero, otherwise non-zero. */
+
+static int update_B(struct csa *csa, int i, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int ret;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* new i-th column of B is k-th column of I */
+         int ind[1+1];
+         double val[1+1];
+         ind[1] = k;
+         val[1] = 1.0;
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
+      }
+      else
+      {  /* new i-th column of B is (k-m)-th column of (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         double *val = csa->work1;
+         int beg, end, ptr, len;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         len = 0;
+         for (ptr = beg; ptr < end; ptr++)
+            val[++len] = - A_val[ptr];
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
+      }
+      csa->valid = (ret == 0);
+      return ret;
+}
+
+/***********************************************************************
+*  error_ftran - compute residual vector r = h - B * x
+*
+*  This routine computes the residual vector r = h - B * x, where B is
+*  the current basis matrix, h is the vector of right-hand sides, x is
+*  the solution vector. */
+
+static void error_ftran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector:
+         r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
+         where B[1], ..., B[m] are columns of matrix B */
+      memcpy(&r[1], &h[1], m * sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  temp = x[i];
+         if (temp == 0.0) continue;
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            r[k] -= temp;
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               r[A_ind[ptr]] += A_val[ptr] * temp;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  refine_ftran - refine solution of B * x = h
+*
+*  This routine performs one iteration to refine the solution of
+*  the system B * x = h, where B is the current basis matrix, h is the
+*  vector of right-hand sides, x is the solution vector. */
+
+static void refine_ftran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B * x */
+      error_ftran(csa, h, x, r);
+      /* compute the correction vector d = inv(B) * r */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+
+/***********************************************************************
+*  error_btran - compute residual vector r = h - B'* x
+*
+*  This routine computes the residual vector r = h - B'* x, where B'
+*  is a matrix transposed to the current basis matrix, h is the vector
+*  of right-hand sides, x is the solution vector. */
+
+static void error_btran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector r = b - B'* x */
+      for (i = 1; i <= m; i++)
+      {  /* r[i] := b[i] - (i-th column of B)'* x */
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         temp = h[i];
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            temp -= x[k];
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               temp += A_val[ptr] * x[A_ind[ptr]];
+         }
+         r[i] = temp;
+      }
+      return;
+}
+
+/***********************************************************************
+*  refine_btran - refine solution of B'* x = h
+*
+*  This routine performs one iteration to refine the solution of the
+*  system B'* x = h, where B' is a matrix transposed to the current
+*  basis matrix, h is the vector of right-hand sides, x is the solution
+*  vector. */
+
+static void refine_btran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B'* x */
+      error_btran(csa, h, x, r);
+      /* compute the correction vector d = inv(B') * r */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+
+/***********************************************************************
+*  alloc_N - allocate matrix N
+*
+*  This routine determines maximal row lengths of matrix N, sets its
+*  row pointers, and then allocates arrays N_ind and N_val.
+*
+*  Note that some fixed structural variables may temporarily become
+*  double-bounded, so corresponding columns of matrix A should not be
+*  ignored on calculating maximal row lengths of matrix N. */
+
+static void alloc_N(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int i, j, beg, end, ptr;
+      /* determine number of non-zeros in each row of the augmented
+         constraint matrix (I|-A) */
+      for (i = 1; i <= m; i++)
+         N_len[i] = 1;
+      for (j = 1; j <= n; j++)
+      {  beg = A_ptr[j];
+         end = A_ptr[j+1];
+         for (ptr = beg; ptr < end; ptr++)
+            N_len[A_ind[ptr]]++;
+      }
+      /* determine maximal row lengths of matrix N and set its row
+         pointers */
+      N_ptr[1] = 1;
+      for (i = 1; i <= m; i++)
+      {  /* row of matrix N cannot have more than n non-zeros */
+         if (N_len[i] > n) N_len[i] = n;
+         N_ptr[i+1] = N_ptr[i] + N_len[i];
+      }
+      /* now maximal number of non-zeros in matrix N is known */
+      csa->N_ind = xcalloc(N_ptr[m+1], sizeof(int));
+      csa->N_val = xcalloc(N_ptr[m+1], sizeof(double));
+      return;
+}
+
+/***********************************************************************
+*  add_N_col - add column of matrix (I|-A) to matrix N
+*
+*  This routine adds j-th column to matrix N which is k-th column of
+*  the augmented constraint matrix (I|-A). (It is assumed that old j-th
+*  column was previously removed from matrix N.) */
+
+static void add_N_col(struct csa *csa, int j, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int *N_ind = csa->N_ind;
+      double *N_val = csa->N_val;
+      int pos;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         pos = N_ptr[k] + (N_len[k]++);
+#ifdef GLP_DEBUG
+         xassert(pos < N_ptr[k+1]);
+#endif
+         N_ind[pos] = j;
+         N_val[pos] = 1.0;
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int i, beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+         {  i = A_ind[ptr]; /* row number */
+            pos = N_ptr[i] + (N_len[i]++);
+#ifdef GLP_DEBUG
+            xassert(pos < N_ptr[i+1]);
+#endif
+            N_ind[pos] = j;
+            N_val[pos] = - A_val[ptr];
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  del_N_col - remove column of matrix (I|-A) from matrix N
+*
+*  This routine removes j-th column from matrix N which is k-th column
+*  of the augmented constraint matrix (I|-A). */
+
+static void del_N_col(struct csa *csa, int j, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int *N_ind = csa->N_ind;
+      double *N_val = csa->N_val;
+      int pos, head, tail;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         /* find element in k-th row of N */
+         head = N_ptr[k];
+         for (pos = head; N_ind[pos] != j; pos++) /* nop */;
+         /* and remove it from the row list */
+         tail = head + (--N_len[k]);
+#ifdef GLP_DEBUG
+         xassert(pos <= tail);
+#endif
+         N_ind[pos] = N_ind[tail];
+         N_val[pos] = N_val[tail];
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         int i, beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+         {  i = A_ind[ptr]; /* row number */
+            /* find element in i-th row of N */
+            head = N_ptr[i];
+            for (pos = head; N_ind[pos] != j; pos++) /* nop */;
+            /* and remove it from the row list */
+            tail = head + (--N_len[i]);
+#ifdef GLP_DEBUG
+            xassert(pos <= tail);
+#endif
+            N_ind[pos] = N_ind[tail];
+            N_val[pos] = N_val[tail];
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  build_N - build matrix N for current basis
+*
+*  This routine builds matrix N for the current basis from columns
+*  of the augmented constraint matrix (I|-A) corresponding to non-basic
+*  non-fixed variables. */
+
+static void build_N(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int *N_len = csa->N_len;
+      int j, k;
+      /* N := empty matrix */
+      memset(&N_len[1], 0, m * sizeof(int));
+      /* go through non-basic columns of matrix (I|-A) */
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] != GLP_NS)
+         {  /* xN[j] is non-fixed; add j-th column to matrix N which is
+               k-th column of matrix (I|-A) */
+            k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+            xassert(1 <= k && k <= m+n);
+#endif
+            add_N_col(csa, j, k);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  get_xN - determine current value of non-basic variable xN[j]
+*
+*  This routine returns the current value of non-basic variable xN[j],
+*  which is a value of its active bound. */
+
+static double get_xN(struct csa *csa, int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int k;
+      double xN;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      switch (stat[j])
+      {  case GLP_NL:
+            /* x[k] is on its lower bound */
+            xN = lb[k]; break;
+         case GLP_NU:
+            /* x[k] is on its upper bound */
+            xN = ub[k]; break;
+         case GLP_NF:
+            /* x[k] is free non-basic variable */
+            xN = 0.0; break;
+         case GLP_NS:
+            /* x[k] is fixed non-basic variable */
+            xN = lb[k]; break;
+         default:
+            xassert(stat != stat);
+      }
+      return xN;
+}
+
+/***********************************************************************
+*  eval_beta - compute primal values of basic variables
+*
+*  This routine computes current primal values of all basic variables:
+*
+*     beta = - inv(B) * N * xN,
+*
+*  where B is the current basis matrix, N is a matrix built of columns
+*  of matrix (I|-A) corresponding to non-basic variables, and xN is the
+*  vector of current values of non-basic variables. */
+
+static void eval_beta(struct csa *csa, double beta[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      double *h = csa->work2;
+      int i, j, k, beg, end, ptr;
+      double xN;
+      /* compute the right-hand side vector:
+         h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
+         where N[1], ..., N[n] are columns of matrix N */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* determine current value of xN[j] */
+         xN = get_xN(csa, j);
+         if (xN == 0.0) continue;
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            h[k] -= xN;
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               h[A_ind[ptr]] += xN * A_val[ptr];
+         }
+      }
+      /* solve system B * beta = h */
+      memcpy(&beta[1], &h[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, beta);
+      /* and refine the solution */
+      refine_ftran(csa, h, beta);
+      return;
+}
+
+/***********************************************************************
+*  eval_pi - compute vector of simplex multipliers
+*
+*  This routine computes the vector of current simplex multipliers:
+*
+*     pi = inv(B') * cB,
+*
+*  where B' is a matrix transposed to the current basis matrix, cB is
+*  a subvector of objective coefficients at basic variables. */
+
+static void eval_pi(struct csa *csa, double pi[])
+{     int m = csa->m;
+      double *c = csa->coef;
+      int *head = csa->head;
+      double *cB = csa->work2;
+      int i;
+      /* construct the right-hand side vector cB */
+      for (i = 1; i <= m; i++)
+         cB[i] = c[head[i]];
+      /* solve system B'* pi = cB */
+      memcpy(&pi[1], &cB[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, pi);
+      /* and refine the solution */
+      refine_btran(csa, cB, pi);
+      return;
+}
+
+/***********************************************************************
+*  eval_cost - compute reduced cost of non-basic variable xN[j]
+*
+*  This routine computes the current reduced cost of non-basic variable
+*  xN[j]:
+*
+*     d[j] = cN[j] - N'[j] * pi,
+*
+*  where cN[j] is the objective coefficient at variable xN[j], N[j] is
+*  a column of the augmented constraint matrix (I|-A) corresponding to
+*  xN[j], pi is the vector of simplex multipliers. */
+
+static double eval_cost(struct csa *csa, double pi[], int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int k;
+      double dj;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      dj = coef[k];
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         dj -= pi[k];
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            dj += A_val[ptr] * pi[A_ind[ptr]];
+      }
+      return dj;
+}
+
+/***********************************************************************
+*  eval_bbar - compute and store primal values of basic variables
+*
+*  This routine computes primal values of all basic variables and then
+*  stores them in the solution array. */
+
+static void eval_bbar(struct csa *csa)
+{     eval_beta(csa, csa->bbar);
+      return;
+}
+
+/***********************************************************************
+*  eval_cbar - compute and store reduced costs of non-basic variables
+*
+*  This routine computes reduced costs of all non-basic variables and
+*  then stores them in the solution array. */
+
+static void eval_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+#endif
+      int n = csa->n;
+#ifdef GLP_DEBUG
+      int *head = csa->head;
+#endif
+      double *cbar = csa->cbar;
+      double *pi = csa->work3;
+      int j;
+#ifdef GLP_DEBUG
+      int k;
+#endif
+      /* compute simplex multipliers */
+      eval_pi(csa, pi);
+      /* compute and store reduced costs */
+      for (j = 1; j <= n; j++)
+      {
+#ifdef GLP_DEBUG
+         k = head[m+j]; /* x[k] = xN[j] */
+         xassert(1 <= k && k <= m+n);
+#endif
+         cbar[j] = eval_cost(csa, pi, j);
+      }
+      return;
+}
+
+/***********************************************************************
+*  reset_refsp - reset the reference space
+*
+*  This routine resets (redefines) the reference space used in the
+*  projected steepest edge pricing algorithm. */
+
+static void reset_refsp(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int j, k;
+      xassert(csa->refct == 0);
+      csa->refct = 1000;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+         refsp[k] = 1;
+         gamma[j] = 1.0;
+      }
+      return;
+}
+
+/***********************************************************************
+*  eval_gamma - compute steepest edge coefficient
+*
+*  This routine computes the steepest edge coefficient for non-basic
+*  variable xN[j] using its direct definition:
+*
+*     gamma[j] = delta[j] +  sum   alfa[i,j]^2,
+*                           i in R
+*
+*  where delta[j] = 1, if xN[j] is in the current reference space,
+*  and 0 otherwise; R is a set of basic variables xB[i], which are in
+*  the current reference space; alfa[i,j] are elements of the current
+*  simplex table.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double eval_gamma(struct csa *csa, int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *alfa = csa->work3;
+      double *h = csa->work3;
+      int i, k;
+      double gamma;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[j] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* solve system B * alfa = h */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, alfa);
+      /* compute gamma */
+      gamma = (refsp[k] ? 1.0 : 0.0);
+      for (i = 1; i <= m; i++)
+      {  k = head[i];
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (refsp[k]) gamma += alfa[i] * alfa[i];
+      }
+      return gamma;
+}
+
+/***********************************************************************
+*  chuzc - choose non-basic variable (column of the simplex table)
+*
+*  This routine chooses non-basic variable xN[q], which has largest
+*  weighted reduced cost:
+*
+*     |d[q]| / sqrt(gamma[q]) = max  |d[j]| / sqrt(gamma[j]),
+*                              j in J
+*
+*  where J is a subset of eligible non-basic variables xN[j], d[j] is
+*  reduced cost of xN[j], gamma[j] is the steepest edge coefficient.
+*
+*  The working objective function is always minimized, so the sign of
+*  d[q] determines direction, in which xN[q] has to change:
+*
+*     if d[q] < 0, xN[q] has to increase;
+*
+*     if d[q] > 0, xN[q] has to decrease.
+*
+*  If |d[j]| <= tol_dj, where tol_dj is a specified tolerance, xN[j]
+*  is not included in J and therefore ignored. (It is assumed that the
+*  working objective row is appropriately scaled, i.e. max|c[k]| = 1.)
+*
+*  If J is empty and no variable has been chosen, q is set to 0. */
+
+static void chuzc(struct csa *csa, double tol_dj)
+{     int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      double *gamma = csa->gamma;
+      int j, q;
+      double dj, best, temp;
+      /* nothing is chosen so far */
+      q = 0, best = 0.0;
+      /* look through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  dj = cbar[j];
+         switch (stat[j])
+         {  case GLP_NL:
+               /* xN[j] can increase */
+               if (dj >= - tol_dj) continue;
+               break;
+            case GLP_NU:
+               /* xN[j] can decrease */
+               if (dj <= + tol_dj) continue;
+               break;
+            case GLP_NF:
+               /* xN[j] can change in any direction */
+               if (- tol_dj <= dj && dj <= + tol_dj) continue;
+               break;
+            case GLP_NS:
+               /* xN[j] cannot change at all */
+               continue;
+            default:
+               xassert(stat != stat);
+         }
+         /* xN[j] is eligible non-basic variable; choose one which has
+            largest weighted reduced cost */
+#ifdef GLP_DEBUG
+         xassert(gamma[j] > 0.0);
+#endif
+         temp = (dj * dj) / gamma[j];
+         if (best < temp)
+            q = j, best = temp;
+      }
+      /* store the index of non-basic variable xN[q] chosen */
+      csa->q = q;
+      return;
+}
+
+/***********************************************************************
+*  eval_tcol - compute pivot column of the simplex table
+*
+*  This routine computes the pivot column of the simplex table, which
+*  corresponds to non-basic variable xN[q] chosen.
+*
+*  The pivot column is the following vector:
+*
+*     tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+*
+*  where B is the current basis matrix, N[q] is a column of the matrix
+*  (I|-A) corresponding to variable xN[q]. */
+
+static void eval_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->tcol_vec;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* solve system B * tcol = h */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  refine_tcol - refine pivot column of the simplex table
+*
+*  This routine refines the pivot column of the simplex table assuming
+*  that it was previously computed by the routine eval_tcol. */
+
+static void refine_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->work3;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* refine solution of B * tcol = h */
+      refine_ftran(csa, h, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  sort_tcol - sort pivot column of the simplex table
+*
+*  This routine reorders the list of non-zero elements of the pivot
+*  column to put significant elements, whose magnitude is not less than
+*  a specified tolerance, in front of the list, and stores the number
+*  of significant elements in tcol_num. */
+
+static void sort_tcol(struct csa *csa, double tol_piv)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+#endif
+      int nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int i, num, pos;
+      double big, eps, temp;
+      /* compute infinity (maximum) norm of the column */
+      big = 0.0;
+      for (pos = 1; pos <= nnz; pos++)
+      {
+#ifdef GLP_DEBUG
+         i = tcol_ind[pos];
+         xassert(1 <= i && i <= m);
+#endif
+         temp = fabs(tcol_vec[tcol_ind[pos]]);
+         if (big < temp) big = temp;
+      }
+      csa->tcol_max = big;
+      /* determine absolute pivot tolerance */
+      eps = tol_piv * (1.0 + 0.01 * big);
+      /* move significant column components to front of the list */
+      for (num = 0; num < nnz; )
+      {  i = tcol_ind[nnz];
+         if (fabs(tcol_vec[i]) < eps)
+            nnz--;
+         else
+         {  num++;
+            tcol_ind[nnz] = tcol_ind[num];
+            tcol_ind[num] = i;
+         }
+      }
+      csa->tcol_num = num;
+      return;
+}
+
+/***********************************************************************
+*  chuzr - choose basic variable (row of the simplex table)
+*
+*  This routine chooses basic variable xB[p], which reaches its bound
+*  first on changing non-basic variable xN[q] in valid direction.
+*
+*  The parameter rtol is a relative tolerance used to relax bounds of
+*  basic variables. If rtol = 0, the routine implements the standard
+*  ratio test. Otherwise, if rtol > 0, the routine implements Harris'
+*  two-pass ratio test. In the latter case rtol should be about three
+*  times less than a tolerance used to check primal feasibility. */
+
+static void chuzr(struct csa *csa, double rtol)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int phase = csa->phase;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int tcol_num = csa->tcol_num;
+      int i, i_stat, k, p, p_stat, pos;
+      double alfa, big, delta, s, t, teta, tmax;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      /* s := - sign(d[q]), where d[q] is reduced cost of xN[q] */
+#ifdef GLP_DEBUG
+      xassert(cbar[q] != 0.0);
+#endif
+      s = (cbar[q] > 0.0 ? -1.0 : +1.0);
+      /*** FIRST PASS ***/
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (type[k] == GLP_DB)
+      {  /* xN[q] has both lower and upper bounds */
+         p = -1, p_stat = 0, teta = ub[k] - lb[k], big = 1.0;
+      }
+      else
+      {  /* xN[q] has no opposite bound */
+         p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
+      }
+      /* walk through significant elements of the pivot column */
+      for (pos = 1; pos <= tcol_num; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         alfa = s * tcol_vec[i];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
+            consider the only case when xN[q] is increasing */
+         if (alfa > 0.0)
+         {  /* xB[i] is increasing */
+            if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               delta = rtol * (1.0 + kappa * fabs(lb[k]));
+               t = ((lb[k] + delta) - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_UP || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an upper bound */
+               delta = rtol * (1.0 + kappa * fabs(ub[k]));
+               t = ((ub[k] + delta) - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no upper bound */
+               continue;
+            }
+         }
+         else
+         {  /* xB[i] is decreasing */
+            if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               delta = rtol * (1.0 + kappa * fabs(ub[k]));
+               t = ((ub[k] - delta) - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_LO || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an lower bound */
+               delta = rtol * (1.0 + kappa * fabs(lb[k]));
+               t = ((lb[k] - delta) - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no lower bound */
+               continue;
+            }
+         }
+         /* t is a change of xN[q], on which xB[i] reaches its bound
+            (possibly relaxed); since the basic solution is assumed to
+            be primal feasible (or pseudo feasible on phase I), t has
+            to be non-negative by definition; however, it may happen
+            that xB[i] slightly (i.e. within a tolerance) violates its
+            bound, that leads to negative t; in the latter case, if
+            xB[i] is chosen, negative t means that xN[q] changes in
+            wrong direction; if pivot alfa[i,q] is close to zero, even
+            small bound violation of xB[i] may lead to a large change
+            of xN[q] in wrong direction; let, for example, xB[i] >= 0
+            and in the current basis its value be -5e-9; let also xN[q]
+            be on its zero bound and should increase; from the ratio
+            test rule it follows that the pivot alfa[i,q] < 0; however,
+            if alfa[i,q] is, say, -1e-9, the change of xN[q] in wrong
+            direction is 5e-9 / (-1e-9) = -5, and using it for updating
+            values of other basic variables will give absolutely wrong
+            results; therefore, if t is negative, we should replace it
+            by exact zero assuming that xB[i] is exactly on its bound,
+            and the violation appears due to round-off errors */
+         if (t < 0.0) t = 0.0;
+         /* apply minimal ratio test */
+         if (teta > t || teta == t && big < fabs(alfa))
+            p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
+      }
+      /* the second pass is skipped in the following cases: */
+      /* if the standard ratio test is used */
+      if (rtol == 0.0) goto done;
+      /* if xN[q] reaches its opposite bound or if no basic variable
+         has been chosen on the first pass */
+      if (p <= 0) goto done;
+      /* if xB[p] is a blocking variable, i.e. if it prevents xN[q]
+         from any change */
+      if (teta == 0.0) goto done;
+      /*** SECOND PASS ***/
+      /* here tmax is a maximal change of xN[q], on which the solution
+         remains primal feasible (or pseudo feasible on phase I) within
+         a tolerance */
+#if 0
+      tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
+#else
+      tmax = teta;
+#endif
+      /* nothing is chosen so far */
+      p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through significant elements of the pivot column */
+      for (pos = 1; pos <= tcol_num; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         alfa = s * tcol_vec[i];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to
+            consider the only case when xN[q] is increasing */
+         if (alfa > 0.0)
+         {  /* xB[i] is increasing */
+            if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               t = (lb[k] - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_UP || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an upper bound */
+               t = (ub[k] - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no upper bound */
+               continue;
+            }
+         }
+         else
+         {  /* xB[i] is decreasing */
+            if (phase == 1 && coef[k] > 0.0)
+            {  /* xB[i] violates its upper bound, which plays the role
+                  of an lower bound on phase I */
+               t = (ub[k] - bbar[i]) / alfa;
+               i_stat = GLP_NU;
+            }
+            else if (phase == 1 && coef[k] < 0.0)
+            {  /* xB[i] violates its lower bound, which plays the role
+                  of an upper bound on phase I */
+               continue;
+            }
+            else if (type[k] == GLP_LO || type[k] == GLP_DB ||
+                     type[k] == GLP_FX)
+            {  /* xB[i] is within its bounds and has an lower bound */
+               t = (lb[k] - bbar[i]) / alfa;
+               i_stat = GLP_NL;
+            }
+            else
+            {  /* xB[i] is within its bounds and has no lower bound */
+               continue;
+            }
+         }
+         /* (see comments for the first pass) */
+         if (t < 0.0) t = 0.0;
+         /* t is a change of xN[q], on which xB[i] reaches its bound;
+            if t <= tmax, all basic variables can violate their bounds
+            only within relaxation tolerance delta; we can use this
+            freedom and choose basic variable having largest influence
+            coefficient to avoid possible numeric instability */
+         if (t <= tmax && big < fabs(alfa))
+            p = i, p_stat = i_stat, teta = t, big = fabs(alfa);
+      }
+      /* something must be chosen on the second pass */
+      xassert(p != 0);
+done: /* store the index and status of basic variable xB[p] chosen */
+      csa->p = p;
+      if (p > 0 && type[head[p]] == GLP_FX)
+         csa->p_stat = GLP_NS;
+      else
+         csa->p_stat = p_stat;
+      /* store corresponding change of non-basic variable xN[q] */
+#ifdef GLP_DEBUG
+      xassert(teta >= 0.0);
+#endif
+      csa->teta = s * teta;
+      return;
+}
+
+/***********************************************************************
+*  eval_rho - compute pivot row of the inverse
+*
+*  This routine computes the pivot (p-th) row of the inverse inv(B),
+*  which corresponds to basic variable xB[p] chosen:
+*
+*     rho = inv(B') * e[p],
+*
+*  where B' is a matrix transposed to the current basis matrix, e[p]
+*  is unity vector. */
+
+static void eval_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = rho;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* solve system B'* rho = e[p] */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, rho);
+      return;
+}
+
+/***********************************************************************
+*  refine_rho - refine pivot row of the inverse
+*
+*  This routine refines the pivot row of the inverse inv(B) assuming
+*  that it was previously computed by the routine eval_rho. */
+
+static void refine_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = csa->work3;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* refine solution of B'* rho = e[p] */
+      refine_btran(csa, e, rho);
+      return;
+}
+
+/***********************************************************************
+*  eval_trow - compute pivot row of the simplex table
+*
+*  This routine computes the pivot row of the simplex table, which
+*  corresponds to basic variable xB[p] chosen.
+*
+*  The pivot row is the following vector:
+*
+*     trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
+*
+*  where rho is the pivot row of the inverse inv(B) previously computed
+*  by the routine eval_rho.
+*
+*  Note that elements of the pivot row corresponding to fixed non-basic
+*  variables are not computed. */
+
+static void eval_trow(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int n = csa->n;
+#ifdef GLP_DEBUG
+      char *stat = csa->stat;
+#endif
+      int *N_ptr = csa->N_ptr;
+      int *N_len = csa->N_len;
+      int *N_ind = csa->N_ind;
+      double *N_val = csa->N_val;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int i, j, beg, end, ptr, nnz;
+      double temp;
+      /* clear the pivot row */
+      for (j = 1; j <= n; j++)
+         trow_vec[j] = 0.0;
+      /* compute the pivot row as a linear combination of rows of the
+         matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
+      for (i = 1; i <= m; i++)
+      {  temp = rho[i];
+         if (temp == 0.0) continue;
+         /* trow := trow - rho[i] * N'[i] */
+         beg = N_ptr[i];
+         end = beg + N_len[i];
+         for (ptr = beg; ptr < end; ptr++)
+         {
+#ifdef GLP_DEBUG
+            j = N_ind[ptr];
+            xassert(1 <= j && j <= n);
+            xassert(stat[j] != GLP_NS);
+#endif
+            trow_vec[N_ind[ptr]] -= temp * N_val[ptr];
+         }
+      }
+      /* construct sparse pattern of the pivot row */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  if (trow_vec[j] != 0.0)
+            trow_ind[++nnz] = j;
+      }
+      csa->trow_nnz = nnz;
+      return;
+}
+
+/***********************************************************************
+*  update_bbar - update values of basic variables
+*
+*  This routine updates values of all basic variables for the adjacent
+*  basis. */
+
+static void update_bbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+      int n = csa->n;
+#endif
+      double *bbar = csa->bbar;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int p = csa->p;
+      double teta = csa->teta;
+      int i, pos;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+      xassert(p < 0 || 1 <= p && p <= m);
+#endif
+      /* if xN[q] leaves the basis, compute its value in the adjacent
+         basis, where it will replace xB[p] */
+      if (p > 0)
+         bbar[p] = get_xN(csa, q) + teta;
+      /* update values of other basic variables (except xB[p], because
+         it will be replaced by xN[q]) */
+      if (teta == 0.0) goto done;
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+         /* skip xB[p] */
+         if (i == p) continue;
+         /* (change of xB[i]) = alfa[i,q] * (change of xN[q]) */
+         bbar[i] += tcol_vec[i] * teta;
+      }
+done: return;
+}
+
+/***********************************************************************
+*  reeval_cost - recompute reduced cost of non-basic variable xN[q]
+*
+*  This routine recomputes reduced cost of non-basic variable xN[q] for
+*  the current basis more accurately using its direct definition:
+*
+*     d[q] = cN[q] - N'[q] * pi =
+*
+*          = cN[q] - N'[q] * (inv(B') * cB) =
+*
+*          = cN[q] - (cB' * inv(B) * N[q]) =
+*
+*          = cN[q] + cB' * (pivot column).
+*
+*  It is assumed that the pivot column of the simplex table is already
+*  computed. */
+
+static double reeval_cost(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int i, pos;
+      double dq;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      dq = coef[head[m+q]];
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         dq += coef[head[i]] * tcol_vec[i];
+      }
+      return dq;
+}
+
+/***********************************************************************
+*  update_cbar - update reduced costs of non-basic variables
+*
+*  This routine updates reduced costs of all (except fixed) non-basic
+*  variables for the adjacent basis. */
+
+static void update_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *cbar = csa->cbar;
+      int q = csa->q;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int j, pos;
+      double new_dq;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      /* compute reduced cost of xB[p] in the adjacent basis, where it
+         will replace xN[q] */
+#ifdef GLP_DEBUG
+      xassert(trow_vec[q] != 0.0);
+#endif
+      new_dq = (cbar[q] /= trow_vec[q]);
+      /* update reduced costs of other non-basic variables (except
+         xN[q], because it will be replaced by xB[p]) */
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+         /* skip xN[q] */
+         if (j == q) continue;
+         cbar[j] -= trow_vec[j] * new_dq;
+      }
+      return;
+}
+
+/***********************************************************************
+*  update_gamma - update steepest edge coefficients
+*
+*  This routine updates steepest-edge coefficients for the adjacent
+*  basis. */
+
+static void update_gamma(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int p = csa->p;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      double *u = csa->work3;
+      int i, j, k, pos, beg, end, ptr;
+      double gamma_q, delta_q, pivot, s, t, t1, t2;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* the basis changes, so decrease the count */
+      xassert(csa->refct > 0);
+      csa->refct--;
+      /* recompute gamma[q] for the current basis more accurately and
+         compute auxiliary vector u */
+      gamma_q = delta_q = (refsp[head[m+q]] ? 1.0 : 0.0);
+      for (i = 1; i <= m; i++) u[i] = 0.0;
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+         if (refsp[head[i]])
+         {  u[i] = t = tcol_vec[i];
+            gamma_q += t * t;
+         }
+         else
+            u[i] = 0.0;
+      }
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, u);
+      /* update gamma[k] for other non-basic variables (except fixed
+         variables and xN[q], because it will be replaced by xB[p]) */
+      pivot = trow_vec[q];
+#ifdef GLP_DEBUG
+      xassert(pivot != 0.0);
+#endif
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+         /* skip xN[q] */
+         if (j == q) continue;
+         /* compute t */
+         t = trow_vec[j] / pivot;
+         /* compute inner product s = N'[j] * u */
+         k = head[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+            s = u[k];
+         else
+         {  s = 0.0;
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               s -= A_val[ptr] * u[A_ind[ptr]];
+         }
+         /* compute gamma[k] for the adjacent basis */
+         t1 = gamma[j] + t * t * gamma_q + 2.0 * t * s;
+         t2 = (refsp[k] ? 1.0 : 0.0) + delta_q * t * t;
+         gamma[j] = (t1 >= t2 ? t1 : t2);
+         if (gamma[j] < DBL_EPSILON) gamma[j] = DBL_EPSILON;
+      }
+      /* compute gamma[q] for the adjacent basis */
+      if (type[head[p]] == GLP_FX)
+         gamma[q] = 1.0;
+      else
+      {  gamma[q] = gamma_q / (pivot * pivot);
+         if (gamma[q] < DBL_EPSILON) gamma[q] = DBL_EPSILON;
+      }
+      return;
+}
+
+/***********************************************************************
+*  err_in_bbar - compute maximal relative error in primal solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |beta[i] - bbar[i]| / (1 + |beta[i]|),
+*
+*  where beta and bbar are, respectively, directly computed and the
+*  current (updated) values of basic variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_bbar(struct csa *csa)
+{     int m = csa->m;
+      double *bbar = csa->bbar;
+      int i;
+      double e, emax, *beta;
+      beta = xcalloc(1+m, sizeof(double));
+      eval_beta(csa, beta);
+      emax = 0.0;
+      for (i = 1; i <= m; i++)
+      {  e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
+         if (emax < e) emax = e;
+      }
+      xfree(beta);
+      return emax;
+}
+
+/***********************************************************************
+*  err_in_cbar - compute maximal relative error in dual solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |cost[j] - cbar[j]| / (1 + |cost[j]|),
+*
+*  where cost and cbar are, respectively, directly computed and the
+*  current (updated) reduced costs of non-basic non-fixed variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_cbar(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j;
+      double e, emax, cost, *pi;
+      pi = xcalloc(1+m, sizeof(double));
+      eval_pi(csa, pi);
+      emax = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS) continue;
+         cost = eval_cost(csa, pi, j);
+         e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
+         if (emax < e) emax = e;
+      }
+      xfree(pi);
+      return emax;
+}
+
+/***********************************************************************
+*  err_in_gamma - compute maximal relative error in steepest edge cff.
+*
+*  This routine returns maximal relative error:
+*
+*     max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
+*
+*  where gamma'[j] and gamma[j] are, respectively, directly computed
+*  and the current (updated) steepest edge coefficients for non-basic
+*  non-fixed variable x[j].
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_gamma(struct csa *csa)
+{     int n = csa->n;
+      char *stat = csa->stat;
+      double *gamma = csa->gamma;
+      int j;
+      double e, emax, temp;
+      emax = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS)
+         {  xassert(gamma[j] == 1.0);
+            continue;
+         }
+         temp = eval_gamma(csa, j);
+         e = fabs(temp - gamma[j]) / (1.0 + fabs(temp));
+         if (emax < e) emax = e;
+      }
+      return emax;
+}
+
+/***********************************************************************
+*  change_basis - change basis header
+*
+*  This routine changes the basis header to make it corresponding to
+*  the adjacent basis. */
+
+static void change_basis(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+      char *type = csa->type;
+#endif
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int q = csa->q;
+      int p = csa->p;
+      int p_stat = csa->p_stat;
+      int k;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      if (p < 0)
+      {  /* xN[q] goes to its opposite bound */
+#ifdef GLP_DEBUG
+         k = head[m+q]; /* x[k] = xN[q] */
+         xassert(1 <= k && k <= m+n);
+         xassert(type[k] == GLP_DB);
+#endif
+         switch (stat[q])
+         {  case GLP_NL:
+               /* xN[q] increases */
+               stat[q] = GLP_NU;
+               break;
+            case GLP_NU:
+               /* xN[q] decreases */
+               stat[q] = GLP_NL;
+               break;
+            default:
+               xassert(stat != stat);
+         }
+      }
+      else
+      {  /* xB[p] leaves the basis, xN[q] enters the basis */
+#ifdef GLP_DEBUG
+         xassert(1 <= p && p <= m);
+         k = head[p]; /* x[k] = xB[p] */
+         switch (p_stat)
+         {  case GLP_NL:
+               /* xB[p] goes to its lower bound */
+               xassert(type[k] == GLP_LO || type[k] == GLP_DB);
+               break;
+            case GLP_NU:
+               /* xB[p] goes to its upper bound */
+               xassert(type[k] == GLP_UP || type[k] == GLP_DB);
+               break;
+            case GLP_NS:
+               /* xB[p] goes to its fixed value */
+               xassert(type[k] == GLP_NS);
+               break;
+            default:
+               xassert(p_stat != p_stat);
+         }
+#endif
+         /* xB[p] <-> xN[q] */
+         k = head[p], head[p] = head[m+q], head[m+q] = k;
+         stat[q] = (char)p_stat;
+      }
+      return;
+}
+
+/***********************************************************************
+*  set_aux_obj - construct auxiliary objective function
+*
+*  The auxiliary objective function is a separable piecewise linear
+*  convex function, which is the sum of primal infeasibilities:
+*
+*     z = t[1] + ... + t[m+n] -> minimize,
+*
+*  where:
+*
+*            / lb[k] - x[k], if x[k] < lb[k]
+*            |
+*     t[k] = <  0, if lb[k] <= x[k] <= ub[k]
+*            |
+*            \ x[k] - ub[k], if x[k] > ub[k]
+*
+*  This routine computes objective coefficients for the current basis
+*  and returns the number of non-zero terms t[k]. */
+
+static int set_aux_obj(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, k, cnt = 0;
+      double eps;
+      /* use a bit more restrictive tolerance */
+      tol_bnd *= 0.90;
+      /* clear all objective coefficients */
+      for (k = 1; k <= m+n; k++)
+         coef[k] = 0.0;
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+         if (type[k] == GLP_LO || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has lower bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] < lb[k] - eps)
+            {  /* and violates it */
+               coef[k] = -1.0;
+               cnt++;
+            }
+         }
+         if (type[k] == GLP_UP || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has upper bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] > ub[k] + eps)
+            {  /* and violates it */
+               coef[k] = +1.0;
+               cnt++;
+            }
+         }
+      }
+      return cnt;
+}
+
+/***********************************************************************
+*  set_orig_obj - restore original objective function
+*
+*  This routine assigns scaled original objective coefficients to the
+*  working objective function. */
+
+static void set_orig_obj(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *coef = csa->coef;
+      double *obj = csa->obj;
+      double zeta = csa->zeta;
+      int i, j;
+      for (i = 1; i <= m; i++)
+         coef[i] = 0.0;
+      for (j = 1; j <= n; j++)
+         coef[m+j] = zeta * obj[j];
+      return;
+}
+
+/***********************************************************************
+*  check_stab - check numerical stability of basic solution
+*
+*  If the current basic solution is primal feasible (or pseudo feasible
+*  on phase I) within a tolerance, this routine returns zero, otherwise
+*  it returns non-zero. */
+
+static int check_stab(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int phase = csa->phase;
+      double *bbar = csa->bbar;
+      int i, k;
+      double eps;
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (phase == 1 && coef[k] < 0.0)
+         {  /* x[k] must not be greater than its lower bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] > lb[k] + eps) return 1;
+         }
+         else if (phase == 1 && coef[k] > 0.0)
+         {  /* x[k] must not be less than its upper bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] < ub[k] - eps) return 1;
+         }
+         else
+         {  /* either phase = 1 and coef[k] = 0, or phase = 2 */
+            if (type[k] == GLP_LO || type[k] == GLP_DB ||
+                type[k] == GLP_FX)
+            {  /* x[k] must not be less than its lower bound */
+               eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+               if (bbar[i] < lb[k] - eps) return 1;
+            }
+            if (type[k] == GLP_UP || type[k] == GLP_DB ||
+                type[k] == GLP_FX)
+            {  /* x[k] must not be greater then its upper bound */
+               eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+               if (bbar[i] > ub[k] + eps) return 1;
+            }
+         }
+      }
+      /* basic solution is primal feasible within a tolerance */
+      return 0;
+}
+
+/***********************************************************************
+*  check_feas - check primal feasibility of basic solution
+*
+*  If the current basic solution is primal feasible within a tolerance,
+*  this routine returns zero, otherwise it returns non-zero. */
+
+static int check_feas(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+      char *type = csa->type;
+#endif
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, k;
+      double eps;
+      xassert(csa->phase == 1);
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (coef[k] < 0.0)
+         {  /* check if x[k] still violates its lower bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_LO || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] < lb[k] - eps) return 1;
+         }
+         else if (coef[k] > 0.0)
+         {  /* check if x[k] still violates its upper bound */
+#ifdef GLP_DEBUG
+            xassert(type[k] == GLP_UP || type[k] == GLP_DB ||
+                    type[k] == GLP_FX);
+#endif
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] > ub[k] + eps) return 1;
+         }
+      }
+      /* basic solution is primal feasible within a tolerance */
+      return 0;
+}
+
+/***********************************************************************
+*  eval_obj - compute original objective function
+*
+*  This routine computes the current value of the original objective
+*  function. */
+
+static double eval_obj(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *obj = csa->obj;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, j, k;
+      double sum;
+      sum = obj[0];
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * bbar[i];
+      }
+      /* walk through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * get_xN(csa, j);
+      }
+      return sum;
+}
+
+/***********************************************************************
+*  display - display the search progress
+*
+*  This routine displays some information about the search progress
+*  that includes:
+*
+*  the search phase;
+*
+*  the number of simplex iterations performed by the solver;
+*
+*  the original objective value;
+*
+*  the sum of (scaled) primal infeasibilities;
+*
+*  the number of basic fixed variables. */
+
+static void display(struct csa *csa, const glp_smcp *parm, int spec)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int phase = csa->phase;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, k, cnt;
+      double sum;
+      if (parm->msg_lev < GLP_MSG_ON) goto skip;
+      if (parm->out_dly > 0 &&
+         1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
+         goto skip;
+      if (csa->it_cnt == csa->it_dpy) goto skip;
+      if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
+      /* compute the sum of primal infeasibilities and determine the
+         number of basic fixed variables */
+      sum = 0.0, cnt = 0;
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (type[k] == GLP_LO || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has lower bound */
+            if (bbar[i] < lb[k])
+               sum += (lb[k] - bbar[i]);
+         }
+         if (type[k] == GLP_UP || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* x[k] has upper bound */
+            if (bbar[i] > ub[k])
+               sum += (bbar[i] - ub[k]);
+         }
+         if (type[k] == GLP_FX) cnt++;
+      }
+      xprintf("%c%6d: obj = %17.9e  infeas = %10.3e (%d)\n",
+         phase == 1 ? ' ' : '*', csa->it_cnt, eval_obj(csa), sum, cnt);
+      csa->it_dpy = csa->it_cnt;
+skip: return;
+}
+
+/***********************************************************************
+*  store_sol - store basic solution back to the problem object
+*
+*  This routine stores basic solution components back to the problem
+*  object. */
+
+static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
+      int d_stat, int ray)
+{     int m = csa->m;
+      int n = csa->n;
+      double zeta = csa->zeta;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int i, j, k;
+#ifdef GLP_DEBUG
+      xassert(lp->m == m);
+      xassert(lp->n == n);
+#endif
+      /* basis factorization */
+#ifdef GLP_DEBUG
+      xassert(!lp->valid && lp->bfd == NULL);
+      xassert(csa->valid && csa->bfd != NULL);
+#endif
+      lp->valid = 1, csa->valid = 0;
+      lp->bfd = csa->bfd, csa->bfd = NULL;
+      memcpy(&lp->head[1], &head[1], m * sizeof(int));
+      /* basic solution status */
+      lp->pbs_stat = p_stat;
+      lp->dbs_stat = d_stat;
+      /* objective function value */
+      lp->obj_val = eval_obj(csa);
+      /* simplex iteration count */
+      lp->it_cnt = csa->it_cnt;
+      /* unbounded ray */
+      lp->some = ray;
+      /* basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = GLP_BS;
+            row->bind = i;
+            row->prim = bbar[i] / row->rii;
+            row->dual = 0.0;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = GLP_BS;
+            col->bind = i;
+            col->prim = bbar[i] * col->sjj;
+            col->dual = 0.0;
+         }
+      }
+      /* non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = stat[j];
+            row->bind = 0;
+#if 0
+            row->prim = get_xN(csa, j) / row->rii;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  row->prim = row->lb; break;
+               case GLP_NU:
+                  row->prim = row->ub; break;
+               case GLP_NF:
+                  row->prim = 0.0; break;
+               case GLP_NS:
+                  row->prim = row->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            row->dual = (cbar[j] * row->rii) / zeta;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = stat[j];
+            col->bind = 0;
+#if 0
+            col->prim = get_xN(csa, j) * col->sjj;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  col->prim = col->lb; break;
+               case GLP_NU:
+                  col->prim = col->ub; break;
+               case GLP_NF:
+                  col->prim = 0.0; break;
+               case GLP_NS:
+                  col->prim = col->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            col->dual = (cbar[j] / col->sjj) / zeta;
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  free_csa - deallocate common storage area
+*
+*  This routine frees all the memory allocated to arrays in the common
+*  storage area (CSA). */
+
+static void free_csa(struct csa *csa)
+{     xfree(csa->type);
+      xfree(csa->lb);
+      xfree(csa->ub);
+      xfree(csa->coef);
+      xfree(csa->obj);
+      xfree(csa->A_ptr);
+      xfree(csa->A_ind);
+      xfree(csa->A_val);
+      xfree(csa->head);
+      xfree(csa->stat);
+      xfree(csa->N_ptr);
+      xfree(csa->N_len);
+      xfree(csa->N_ind);
+      xfree(csa->N_val);
+      xfree(csa->bbar);
+      xfree(csa->cbar);
+      xfree(csa->refsp);
+      xfree(csa->gamma);
+      xfree(csa->tcol_ind);
+      xfree(csa->tcol_vec);
+      xfree(csa->trow_ind);
+      xfree(csa->trow_vec);
+      xfree(csa->work1);
+      xfree(csa->work2);
+      xfree(csa->work3);
+      xfree(csa->work4);
+      xfree(csa);
+      return;
+}
+
+/***********************************************************************
+*  spx_primal - core LP solver based on the primal simplex method
+*
+*  SYNOPSIS
+*
+*  #include "glpspx.h"
+*  int spx_primal(glp_prob *lp, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine spx_primal is a core LP solver based on the two-phase
+*  primal simplex method.
+*
+*  RETURNS
+*
+*  0  LP instance has been successfully solved.
+*
+*  GLP_EITLIM
+*     Iteration limit has been exhausted.
+*
+*  GLP_ETMLIM
+*     Time limit has been exhausted.
+*
+*  GLP_EFAIL
+*     The solver failed to solve LP instance. */
+
+int spx_primal(glp_prob *lp, const glp_smcp *parm)
+{     struct csa *csa;
+      int binv_st = 2;
+      /* status of basis matrix factorization:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int bbar_st = 0;
+      /* status of primal values of basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int cbar_st = 0;
+      /* status of reduced costs of non-basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int rigorous = 0;
+      /* rigorous mode flag; this flag is used to enable iterative
+         refinement on computing pivot rows and columns of the simplex
+         table */
+      int check = 0;
+      int p_stat, d_stat, ret;
+      /* allocate and initialize the common storage area */
+      csa = alloc_csa(lp);
+      init_csa(csa, lp);
+      if (parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Objective scale factor = %g\n", csa->zeta);
+loop: /* main loop starts here */
+      /* compute factorization of the basis matrix */
+      if (binv_st == 0)
+      {  ret = invert_B(csa);
+         if (ret != 0)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+            {  xprintf("Error: unable to factorize the basis matrix (%d"
+                  ")\n", ret);
+               xprintf("Sorry, basis recovery procedure not implemented"
+                  " yet\n");
+            }
+            xassert(!lp->valid && lp->bfd == NULL);
+            lp->bfd = csa->bfd, csa->bfd = NULL;
+            lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+            lp->obj_val = 0.0;
+            lp->it_cnt = csa->it_cnt;
+            lp->some = 0;
+            ret = GLP_EFAIL;
+            goto done;
+         }
+         csa->valid = 1;
+         binv_st = 1; /* just computed */
+         /* invalidate basic solution components */
+         bbar_st = cbar_st = 0;
+      }
+      /* compute primal values of basic variables */
+      if (bbar_st == 0)
+      {  eval_bbar(csa);
+         bbar_st = 1; /* just computed */
+         /* determine the search phase, if not determined yet */
+         if (csa->phase == 0)
+         {  if (set_aux_obj(csa, parm->tol_bnd) > 0)
+            {  /* current basic solution is primal infeasible */
+               /* start to minimize the sum of infeasibilities */
+               csa->phase = 1;
+            }
+            else
+            {  /* current basic solution is primal feasible */
+               /* start to minimize the original objective function */
+               set_orig_obj(csa);
+               csa->phase = 2;
+            }
+            xassert(check_stab(csa, parm->tol_bnd) == 0);
+            /* working objective coefficients have been changed, so
+               invalidate reduced costs */
+            cbar_st = 0;
+            display(csa, parm, 1);
+         }
+         /* make sure that the current basic solution remains primal
+            feasible (or pseudo feasible on phase I) */
+         if (check_stab(csa, parm->tol_bnd))
+         {  /* there are excessive bound violations due to round-off
+               errors */
+            if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: numerical instability (primal simplex,"
+                  " phase %s)\n", csa->phase == 1 ? "I" : "II");
+            /* restart the search */
+            csa->phase = 0;
+            binv_st = 0;
+            rigorous = 5;
+            goto loop;
+         }
+      }
+      xassert(csa->phase == 1 || csa->phase == 2);
+      /* on phase I we do not need to wait until the current basic
+         solution becomes dual feasible; it is sufficient to make sure
+         that no basic variable violates its bounds */
+      if (csa->phase == 1 && !check_feas(csa, parm->tol_bnd))
+      {  /* the current basis is primal feasible; switch to phase II */
+         csa->phase = 2;
+         set_orig_obj(csa);
+         cbar_st = 0;
+         display(csa, parm, 1);
+      }
+      /* compute reduced costs of non-basic variables */
+      if (cbar_st == 0)
+      {  eval_cbar(csa);
+         cbar_st = 1; /* just computed */
+      }
+      /* redefine the reference space, if required */
+      switch (parm->pricing)
+      {  case GLP_PT_STD:
+            break;
+         case GLP_PT_PSE:
+            if (csa->refct == 0) reset_refsp(csa);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      /* at this point the basis factorization and all basic solution
+         components are valid */
+      xassert(binv_st && bbar_st && cbar_st);
+      /* check accuracy of current basic solution components (only for
+         debugging) */
+      if (check)
+      {  double e_bbar = err_in_bbar(csa);
+         double e_cbar = err_in_cbar(csa);
+         double e_gamma =
+            (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
+         xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
+            e_bbar, e_cbar, e_gamma);
+         xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
+      }
+      /* check if the iteration limit has been exhausted */
+      if (parm->it_lim < INT_MAX &&
+          csa->it_cnt - csa->it_beg >= parm->it_lim)
+      {  if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               p_stat = GLP_INFEAS;
+               set_orig_obj(csa);
+               eval_cbar(csa);
+               break;
+            case 2:
+               p_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         chuzc(csa, parm->tol_dj);
+         d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = GLP_EITLIM;
+         goto done;
+      }
+      /* check if the time limit has been exhausted */
+      if (parm->tm_lim < INT_MAX &&
+          1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
+      {  if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (csa->phase == 2 && cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               p_stat = GLP_INFEAS;
+               set_orig_obj(csa);
+               eval_cbar(csa);
+               break;
+            case 2:
+               p_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         chuzc(csa, parm->tol_dj);
+         d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = GLP_ETMLIM;
+         goto done;
+      }
+      /* display the search progress */
+      display(csa, parm, 0);
+      /* choose non-basic variable xN[q] */
+      chuzc(csa, parm->tol_dj);
+      if (csa->q == 0)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+               p_stat = GLP_NOFEAS;
+               set_orig_obj(csa);
+               eval_cbar(csa);
+               chuzc(csa, parm->tol_dj);
+               d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS);
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("OPTIMAL SOLUTION FOUND\n");
+               p_stat = d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = 0;
+         goto done;
+      }
+      /* compute pivot column of the simplex table */
+      eval_tcol(csa);
+      if (rigorous) refine_tcol(csa);
+      sort_tcol(csa, parm->tol_piv);
+      /* check accuracy of the reduced cost of xN[q] */
+      {  double d1 = csa->cbar[csa->q]; /* less accurate */
+         double d2 = reeval_cost(csa);  /* more accurate */
+         xassert(d1 != 0.0);
+         if (fabs(d1 - d2) > 1e-5 * (1.0 + fabs(d2)) ||
+             !(d1 < 0.0 && d2 < 0.0 || d1 > 0.0 && d2 > 0.0))
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("d1 = %.12g; d2 = %.12g\n", d1, d2);
+            if (cbar_st != 1 || !rigorous)
+            {  if (cbar_st != 1) cbar_st = 0;
+               rigorous = 5;
+               goto loop;
+            }
+         }
+         /* replace cbar[q] by more accurate value keeping its sign */
+         if (d1 > 0.0)
+            csa->cbar[csa->q] = (d2 > 0.0 ? d2 : +DBL_EPSILON);
+         else
+            csa->cbar[csa->q] = (d2 < 0.0 ? d2 : -DBL_EPSILON);
+      }
+      /* choose basic variable xB[p] */
+      switch (parm->r_test)
+      {  case GLP_RT_STD:
+            chuzr(csa, 0.0);
+            break;
+         case GLP_RT_HAR:
+            chuzr(csa, 0.30 * parm->tol_bnd);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      if (csa->p == 0)
+      {  if (bbar_st != 1 || cbar_st != 1 || !rigorous)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            rigorous = 1;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("Error: unable to choose basic variable on ph"
+                     "ase I\n");
+               xassert(!lp->valid && lp->bfd == NULL);
+               lp->bfd = csa->bfd, csa->bfd = NULL;
+               lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+               lp->obj_val = 0.0;
+               lp->it_cnt = csa->it_cnt;
+               lp->some = 0;
+               ret = GLP_EFAIL;
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+               store_sol(csa, lp, GLP_FEAS, GLP_NOFEAS,
+                  csa->head[csa->m+csa->q]);
+               ret = 0;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         goto done;
+      }
+      /* check if the pivot element is acceptable */
+      if (csa->p > 0)
+      {  double piv = csa->tcol_vec[csa->p];
+         double eps = 1e-5 * (1.0 + 0.01 * csa->tcol_max);
+         if (fabs(piv) < eps)
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv = %.12g; eps = %g\n", piv, eps);
+            if (!rigorous)
+            {  rigorous = 5;
+               goto loop;
+            }
+         }
+      }
+      /* now xN[q] and xB[p] have been chosen anyhow */
+      /* compute pivot row of the simplex table */
+      if (csa->p > 0)
+      {  double *rho = csa->work4;
+         eval_rho(csa, rho);
+         if (rigorous) refine_rho(csa, rho);
+         eval_trow(csa, rho);
+      }
+      /* accuracy check based on the pivot element */
+      if (csa->p > 0)
+      {  double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
+         double piv2 = csa->trow_vec[csa->q]; /* less accurate */
+         xassert(piv1 != 0.0);
+         if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
+             !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
+            if (binv_st != 1 || !rigorous)
+            {  if (binv_st != 1) binv_st = 0;
+               rigorous = 5;
+               goto loop;
+            }
+            /* use more accurate version in the pivot row */
+            if (csa->trow_vec[csa->q] == 0.0)
+            {  csa->trow_nnz++;
+               xassert(csa->trow_nnz <= csa->n);
+               csa->trow_ind[csa->trow_nnz] = csa->q;
+            }
+            csa->trow_vec[csa->q] = piv1;
+         }
+      }
+      /* update primal values of basic variables */
+      update_bbar(csa);
+      bbar_st = 2; /* updated */
+      /* update reduced costs of non-basic variables */
+      if (csa->p > 0)
+      {  update_cbar(csa);
+         cbar_st = 2; /* updated */
+         /* on phase I objective coefficient of xB[p] in the adjacent
+            basis becomes zero */
+         if (csa->phase == 1)
+         {  int k = csa->head[csa->p]; /* x[k] = xB[p] -> xN[q] */
+            csa->cbar[csa->q] -= csa->coef[k];
+            csa->coef[k] = 0.0;
+         }
+      }
+      /* update steepest edge coefficients */
+      if (csa->p > 0)
+      {  switch (parm->pricing)
+         {  case GLP_PT_STD:
+               break;
+            case GLP_PT_PSE:
+               if (csa->refct > 0) update_gamma(csa);
+               break;
+            default:
+               xassert(parm != parm);
+         }
+      }
+      /* update factorization of the basis matrix */
+      if (csa->p > 0)
+      {  ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
+         if (ret == 0)
+            binv_st = 2; /* updated */
+         else
+         {  csa->valid = 0;
+            binv_st = 0; /* invalid */
+         }
+      }
+      /* update matrix N */
+      if (csa->p > 0)
+      {  del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
+         if (csa->type[csa->head[csa->p]] != GLP_FX)
+            add_N_col(csa, csa->q, csa->head[csa->p]);
+      }
+      /* change the basis header */
+      change_basis(csa);
+      /* iteration complete */
+      csa->it_cnt++;
+      if (rigorous > 0) rigorous--;
+      goto loop;
+done: /* deallocate the common storage area */
+      free_csa(csa);
+      /* return to the calling program */
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpspx02.c
===================================================================
--- deps/glpk/src/glpspx02.c	(revision 9)
+++ deps/glpk/src/glpspx02.c	(revision 9)
@@ -0,0 +1,3077 @@
+/* glpspx02.c (dual simplex method) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpspx.h"
+
+#define GLP_DEBUG 1
+
+#if 0
+#define GLP_LONG_STEP 1
+#endif
+
+struct csa
+{     /* common storage area */
+      /*--------------------------------------------------------------*/
+      /* LP data */
+      int m;
+      /* number of rows (auxiliary variables), m > 0 */
+      int n;
+      /* number of columns (structural variables), n > 0 */
+      char *type; /* char type[1+m+n]; */
+      /* type[0] is not used;
+         type[k], 1 <= k <= m+n, is the type of variable x[k]:
+         GLP_FR - free variable
+         GLP_LO - variable with lower bound
+         GLP_UP - variable with upper bound
+         GLP_DB - double-bounded variable
+         GLP_FX - fixed variable */
+      double *lb; /* double lb[1+m+n]; */
+      /* lb[0] is not used;
+         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
+         if x[k] has no lower bound, lb[k] is zero */
+      double *ub; /* double ub[1+m+n]; */
+      /* ub[0] is not used;
+         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
+         if x[k] has no upper bound, ub[k] is zero;
+         if x[k] is of fixed type, ub[k] is the same as lb[k] */
+      double *coef; /* double coef[1+m+n]; */
+      /* coef[0] is not used;
+         coef[k], 1 <= k <= m+n, is an objective coefficient at
+         variable x[k] */
+      /*--------------------------------------------------------------*/
+      /* original bounds of variables */
+      char *orig_type; /* char orig_type[1+m+n]; */
+      double *orig_lb; /* double orig_lb[1+m+n]; */
+      double *orig_ub; /* double orig_ub[1+m+n]; */
+      /*--------------------------------------------------------------*/
+      /* original objective function */
+      double *obj; /* double obj[1+n]; */
+      /* obj[0] is a constant term of the original objective function;
+         obj[j], 1 <= j <= n, is an original objective coefficient at
+         structural variable x[m+j] */
+      double zeta;
+      /* factor used to scale original objective coefficients; its
+         sign defines original optimization direction: zeta > 0 means
+         minimization, zeta < 0 means maximization */
+      /*--------------------------------------------------------------*/
+      /* constraint matrix A; it has m rows and n columns and is stored
+         by columns */
+      int *A_ptr; /* int A_ptr[1+n+1]; */
+      /* A_ptr[0] is not used;
+         A_ptr[j], 1 <= j <= n, is starting position of j-th column in
+         arrays A_ind and A_val; note that A_ptr[1] is always 1;
+         A_ptr[n+1] indicates the position after the last element in
+         arrays A_ind and A_val */
+      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
+      /* row indices */
+      double *A_val; /* double A_val[A_ptr[n+1]]; */
+      /* non-zero element values */
+#if 1 /* 06/IV-2009 */
+      /* constraint matrix A stored by rows */
+      int *AT_ptr; /* int AT_ptr[1+m+1]; */
+      /* AT_ptr[0] is not used;
+         AT_ptr[i], 1 <= i <= m, is starting position of i-th row in
+         arrays AT_ind and AT_val; note that AT_ptr[1] is always 1;
+         AT_ptr[m+1] indicates the position after the last element in
+         arrays AT_ind and AT_val */
+      int *AT_ind; /* int AT_ind[AT_ptr[m+1]]; */
+      /* column indices */
+      double *AT_val; /* double AT_val[AT_ptr[m+1]]; */
+      /* non-zero element values */
+#endif
+      /*--------------------------------------------------------------*/
+      /* basis header */
+      int *head; /* int head[1+m+n]; */
+      /* head[0] is not used;
+         head[i], 1 <= i <= m, is the ordinal number of basic variable
+         xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of
+         matrix B is k-th column of matrix (I|-A);
+         head[m+j], 1 <= j <= n, is the ordinal number of non-basic
+         variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th
+         column of matrix N is k-th column of matrix (I|-A) */
+#if 1 /* 06/IV-2009 */
+      int *bind; /* int bind[1+m+n]; */
+      /* bind[0] is not used;
+         bind[k], 1 <= k <= m+n, is the position of k-th column of the
+         matrix (I|-A) in the matrix (B|N); that is, bind[k] = k' means
+         that head[k'] = k */
+#endif
+      char *stat; /* char stat[1+n]; */
+      /* stat[0] is not used;
+         stat[j], 1 <= j <= n, is the status of non-basic variable
+         xN[j], which defines its active bound:
+         GLP_NL - lower bound is active
+         GLP_NU - upper bound is active
+         GLP_NF - free variable
+         GLP_NS - fixed variable */
+      /*--------------------------------------------------------------*/
+      /* matrix B is the basis matrix; it is composed from columns of
+         the augmented constraint matrix (I|-A) corresponding to basic
+         variables and stored in a factorized (invertable) form */
+      int valid;
+      /* factorization is valid only if this flag is set */
+      BFD *bfd; /* BFD bfd[1:m,1:m]; */
+      /* factorized (invertable) form of the basis matrix */
+#if 0 /* 06/IV-2009 */
+      /*--------------------------------------------------------------*/
+      /* matrix N is a matrix composed from columns of the augmented
+         constraint matrix (I|-A) corresponding to non-basic variables
+         except fixed ones; it is stored by rows and changes every time
+         the basis changes */
+      int *N_ptr; /* int N_ptr[1+m+1]; */
+      /* N_ptr[0] is not used;
+         N_ptr[i], 1 <= i <= m, is starting position of i-th row in
+         arrays N_ind and N_val; note that N_ptr[1] is always 1;
+         N_ptr[m+1] indicates the position after the last element in
+         arrays N_ind and N_val */
+      int *N_len; /* int N_len[1+m]; */
+      /* N_len[0] is not used;
+         N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */
+      int *N_ind; /* int N_ind[N_ptr[m+1]]; */
+      /* column indices */
+      double *N_val; /* double N_val[N_ptr[m+1]]; */
+      /* non-zero element values */
+#endif
+      /*--------------------------------------------------------------*/
+      /* working parameters */
+      int phase;
+      /* search phase:
+         0 - not determined yet
+         1 - search for dual feasible solution
+         2 - search for optimal solution */
+      glp_long tm_beg;
+      /* time value at the beginning of the search */
+      int it_beg;
+      /* simplex iteration count at the beginning of the search */
+      int it_cnt;
+      /* simplex iteration count; it increases by one every time the
+         basis changes */
+      int it_dpy;
+      /* simplex iteration count at the most recent display output */
+      /*--------------------------------------------------------------*/
+      /* basic solution components */
+      double *bbar; /* double bbar[1+m]; */
+      /* bbar[0] is not used on phase I; on phase II it is the current
+         value of the original objective function;
+         bbar[i], 1 <= i <= m, is primal value of basic variable xB[i]
+         (if xB[i] is free, its primal value is not updated) */
+      double *cbar; /* double cbar[1+n]; */
+      /* cbar[0] is not used;
+         cbar[j], 1 <= j <= n, is reduced cost of non-basic variable
+         xN[j] (if xN[j] is fixed, its reduced cost is not updated) */
+      /*--------------------------------------------------------------*/
+      /* the following pricing technique options may be used:
+         GLP_PT_STD - standard ("textbook") pricing;
+         GLP_PT_PSE - projected steepest edge;
+         GLP_PT_DVX - Devex pricing (not implemented yet);
+         in case of GLP_PT_STD the reference space is not used, and all
+         steepest edge coefficients are set to 1 */
+      int refct;
+      /* this count is set to an initial value when the reference space
+         is defined and decreases by one every time the basis changes;
+         once this count reaches zero, the reference space is redefined
+         again */
+      char *refsp; /* char refsp[1+m+n]; */
+      /* refsp[0] is not used;
+         refsp[k], 1 <= k <= m+n, is the flag which means that variable
+         x[k] belongs to the current reference space */
+      double *gamma; /* double gamma[1+m]; */
+      /* gamma[0] is not used;
+         gamma[i], 1 <= i <= n, is the steepest edge coefficient for
+         basic variable xB[i]; if xB[i] is free, gamma[i] is not used
+         and just set to 1 */
+      /*--------------------------------------------------------------*/
+      /* basic variable xB[p] chosen to leave the basis */
+      int p;
+      /* index of the basic variable xB[p] chosen, 1 <= p <= m;
+         if the set of eligible basic variables is empty (i.e. if the
+         current basic solution is primal feasible within a tolerance)
+         and thus no variable has been chosen, p is set to 0 */
+      double delta;
+      /* change of xB[p] in the adjacent basis;
+         delta > 0 means that xB[p] violates its lower bound and will
+         increase to achieve it in the adjacent basis;
+         delta < 0 means that xB[p] violates its upper bound and will
+         decrease to achieve it in the adjacent basis */
+      /*--------------------------------------------------------------*/
+      /* pivot row of the simplex table corresponding to basic variable
+         xB[p] chosen is the following vector:
+            T' * e[p] = - N' * inv(B') * e[p] = - N' * rho,
+         where B' is a matrix transposed to the current basis matrix,
+         N' is a matrix, whose rows are columns of the matrix (I|-A)
+         corresponding to non-basic non-fixed variables */
+      int trow_nnz;
+      /* number of non-zero components, 0 <= nnz <= n */
+      int *trow_ind; /* int trow_ind[1+n]; */
+      /* trow_ind[0] is not used;
+         trow_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. trow_ind[t] = j means that trow_vec[j] != 0 */
+      double *trow_vec; /* int trow_vec[1+n]; */
+      /* trow_vec[0] is not used;
+         trow_vec[j], 1 <= j <= n, is a numeric value of j-th component
+         of the row */
+      double trow_max;
+      /* infinity (maximum) norm of the row (max |trow_vec[j]|) */
+      int trow_num;
+      /* number of significant non-zero components, which means that:
+         |trow_vec[j]| >= eps for j in trow_ind[1,...,num],
+         |tcol_vec[j]| <  eps for j in trow_ind[num+1,...,nnz],
+         where eps is a pivot tolerance */
+      /*--------------------------------------------------------------*/
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      int nbps;
+      /* number of breakpoints, 0 <= nbps <= n */
+      struct bkpt
+      {     int j;
+            /* index of non-basic variable xN[j], 1 <= j <= n */
+            double t;
+            /* value of dual ray parameter at breakpoint, t >= 0 */
+            double dz;
+            /* dz = zeta(t = t[k]) - zeta(t = 0) */
+      } *bkpt; /* struct bkpt bkpt[1+n]; */
+      /* bkpt[0] is not used;
+         bkpt[k], 1 <= k <= nbps, is k-th breakpoint of the dual
+         objective */
+#endif
+      /*--------------------------------------------------------------*/
+      /* non-basic variable xN[q] chosen to enter the basis */
+      int q;
+      /* index of the non-basic variable xN[q] chosen, 1 <= q <= n;
+         if no variable has been chosen, q is set to 0 */
+      double new_dq;
+      /* reduced cost of xN[q] in the adjacent basis (it is the change
+         of lambdaB[p]) */
+      /*--------------------------------------------------------------*/
+      /* pivot column of the simplex table corresponding to non-basic
+         variable xN[q] chosen is the following vector:
+            T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+         where B is the current basis matrix, N[q] is a column of the
+         matrix (I|-A) corresponding to xN[q] */
+      int tcol_nnz;
+      /* number of non-zero components, 0 <= nnz <= m */
+      int *tcol_ind; /* int tcol_ind[1+m]; */
+      /* tcol_ind[0] is not used;
+         tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component,
+         i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */
+      double *tcol_vec; /* double tcol_vec[1+m]; */
+      /* tcol_vec[0] is not used;
+         tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component
+         of the column */
+      /*--------------------------------------------------------------*/
+      /* working arrays */
+      double *work1; /* double work1[1+m]; */
+      double *work2; /* double work2[1+m]; */
+      double *work3; /* double work3[1+m]; */
+      double *work4; /* double work4[1+m]; */
+};
+
+static const double kappa = 0.10;
+
+/***********************************************************************
+*  alloc_csa - allocate common storage area
+*
+*  This routine allocates all arrays in the common storage area (CSA)
+*  and returns a pointer to the CSA. */
+
+static struct csa *alloc_csa(glp_prob *lp)
+{     struct csa *csa;
+      int m = lp->m;
+      int n = lp->n;
+      int nnz = lp->nnz;
+      csa = xmalloc(sizeof(struct csa));
+      xassert(m > 0 && n > 0);
+      csa->m = m;
+      csa->n = n;
+      csa->type = xcalloc(1+m+n, sizeof(char));
+      csa->lb = xcalloc(1+m+n, sizeof(double));
+      csa->ub = xcalloc(1+m+n, sizeof(double));
+      csa->coef = xcalloc(1+m+n, sizeof(double));
+      csa->orig_type = xcalloc(1+m+n, sizeof(char));
+      csa->orig_lb = xcalloc(1+m+n, sizeof(double));
+      csa->orig_ub = xcalloc(1+m+n, sizeof(double));
+      csa->obj = xcalloc(1+n, sizeof(double));
+      csa->A_ptr = xcalloc(1+n+1, sizeof(int));
+      csa->A_ind = xcalloc(1+nnz, sizeof(int));
+      csa->A_val = xcalloc(1+nnz, sizeof(double));
+#if 1 /* 06/IV-2009 */
+      csa->AT_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->AT_ind = xcalloc(1+nnz, sizeof(int));
+      csa->AT_val = xcalloc(1+nnz, sizeof(double));
+#endif
+      csa->head = xcalloc(1+m+n, sizeof(int));
+#if 1 /* 06/IV-2009 */
+      csa->bind = xcalloc(1+m+n, sizeof(int));
+#endif
+      csa->stat = xcalloc(1+n, sizeof(char));
+#if 0 /* 06/IV-2009 */
+      csa->N_ptr = xcalloc(1+m+1, sizeof(int));
+      csa->N_len = xcalloc(1+m, sizeof(int));
+      csa->N_ind = NULL; /* will be allocated later */
+      csa->N_val = NULL; /* will be allocated later */
+#endif
+      csa->bbar = xcalloc(1+m, sizeof(double));
+      csa->cbar = xcalloc(1+n, sizeof(double));
+      csa->refsp = xcalloc(1+m+n, sizeof(char));
+      csa->gamma = xcalloc(1+m, sizeof(double));
+      csa->trow_ind = xcalloc(1+n, sizeof(int));
+      csa->trow_vec = xcalloc(1+n, sizeof(double));
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      csa->bkpt = xcalloc(1+n, sizeof(struct bkpt));
+#endif
+      csa->tcol_ind = xcalloc(1+m, sizeof(int));
+      csa->tcol_vec = xcalloc(1+m, sizeof(double));
+      csa->work1 = xcalloc(1+m, sizeof(double));
+      csa->work2 = xcalloc(1+m, sizeof(double));
+      csa->work3 = xcalloc(1+m, sizeof(double));
+      csa->work4 = xcalloc(1+m, sizeof(double));
+      return csa;
+}
+
+/***********************************************************************
+*  init_csa - initialize common storage area
+*
+*  This routine initializes all data structures in the common storage
+*  area (CSA). */
+
+static void init_csa(struct csa *csa, glp_prob *lp)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      double *coef = csa->coef;
+      char *orig_type = csa->orig_type;
+      double *orig_lb = csa->orig_lb;
+      double *orig_ub = csa->orig_ub;
+      double *obj = csa->obj;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+#if 1 /* 06/IV-2009 */
+      int *AT_ptr = csa->AT_ptr;
+      int *AT_ind = csa->AT_ind;
+      double *AT_val = csa->AT_val;
+#endif
+      int *head = csa->head;
+#if 1 /* 06/IV-2009 */
+      int *bind = csa->bind;
+#endif
+      char *stat = csa->stat;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int i, j, k, loc;
+      double cmax;
+      /* auxiliary variables */
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         type[i] = (char)row->type;
+         lb[i] = row->lb * row->rii;
+         ub[i] = row->ub * row->rii;
+         coef[i] = 0.0;
+      }
+      /* structural variables */
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         type[m+j] = (char)col->type;
+         lb[m+j] = col->lb / col->sjj;
+         ub[m+j] = col->ub / col->sjj;
+         coef[m+j] = col->coef * col->sjj;
+      }
+      /* original bounds of variables */
+      memcpy(&orig_type[1], &type[1], (m+n) * sizeof(char));
+      memcpy(&orig_lb[1], &lb[1], (m+n) * sizeof(double));
+      memcpy(&orig_ub[1], &ub[1], (m+n) * sizeof(double));
+      /* original objective function */
+      obj[0] = lp->c0;
+      memcpy(&obj[1], &coef[m+1], n * sizeof(double));
+      /* factor used to scale original objective coefficients */
+      cmax = 0.0;
+      for (j = 1; j <= n; j++)
+         if (cmax < fabs(obj[j])) cmax = fabs(obj[j]);
+      if (cmax == 0.0) cmax = 1.0;
+      switch (lp->dir)
+      {  case GLP_MIN:
+            csa->zeta = + 1.0 / cmax;
+            break;
+         case GLP_MAX:
+            csa->zeta = - 1.0 / cmax;
+            break;
+         default:
+            xassert(lp != lp);
+      }
+#if 1
+      if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0;
+#endif
+      /* scale working objective coefficients */
+      for (j = 1; j <= n; j++) coef[m+j] *= csa->zeta;
+      /* matrix A (by columns) */
+      loc = 1;
+      for (j = 1; j <= n; j++)
+      {  GLPAIJ *aij;
+         A_ptr[j] = loc;
+         for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next)
+         {  A_ind[loc] = aij->row->i;
+            A_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      A_ptr[n+1] = loc;
+      xassert(loc-1 == lp->nnz);
+#if 1 /* 06/IV-2009 */
+      /* matrix A (by rows) */
+      loc = 1;
+      for (i = 1; i <= m; i++)
+      {  GLPAIJ *aij;
+         AT_ptr[i] = loc;
+         for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
+         {  AT_ind[loc] = aij->col->j;
+            AT_val[loc] = aij->row->rii * aij->val * aij->col->sjj;
+            loc++;
+         }
+      }
+      AT_ptr[m+1] = loc;
+      xassert(loc-1 == lp->nnz);
+#endif
+      /* basis header */
+      xassert(lp->valid);
+      memcpy(&head[1], &lp->head[1], m * sizeof(int));
+      k = 0;
+      for (i = 1; i <= m; i++)
+      {  GLPROW *row = lp->row[i];
+         if (row->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = i;
+            stat[k] = (char)row->stat;
+         }
+      }
+      for (j = 1; j <= n; j++)
+      {  GLPCOL *col = lp->col[j];
+         if (col->stat != GLP_BS)
+         {  k++;
+            xassert(k <= n);
+            head[m+k] = m + j;
+            stat[k] = (char)col->stat;
+         }
+      }
+      xassert(k == n);
+#if 1 /* 06/IV-2009 */
+      for (k = 1; k <= m+n; k++)
+         bind[head[k]] = k;
+#endif
+      /* factorization of matrix B */
+      csa->valid = 1, lp->valid = 0;
+      csa->bfd = lp->bfd, lp->bfd = NULL;
+#if 0 /* 06/IV-2009 */
+      /* matrix N (by rows) */
+      alloc_N(csa);
+      build_N(csa);
+#endif
+      /* working parameters */
+      csa->phase = 0;
+      csa->tm_beg = xtime();
+      csa->it_beg = csa->it_cnt = lp->it_cnt;
+      csa->it_dpy = -1;
+      /* reference space and steepest edge coefficients */
+      csa->refct = 0;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (i = 1; i <= m; i++) gamma[i] = 1.0;
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  invert_B - compute factorization of the basis matrix
+*
+*  This routine computes factorization of the current basis matrix B.
+*
+*  If the operation is successful, the routine returns zero, otherwise
+*  non-zero. */
+
+static int inv_col(void *info, int i, int ind[], double val[])
+{     /* this auxiliary routine returns row indices and numeric values
+         of non-zero elements of i-th column of the basis matrix */
+      struct csa *csa = info;
+      int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int k, len, ptr, t;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+#endif
+      k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* B[i] is k-th column of submatrix I */
+         len = 1;
+         ind[1] = k;
+         val[1] = 1.0;
+      }
+      else
+      {  /* B[i] is (k-m)-th column of submatrix (-A) */
+         ptr = A_ptr[k-m];
+         len = A_ptr[k-m+1] - ptr;
+         memcpy(&ind[1], &A_ind[ptr], len * sizeof(int));
+         memcpy(&val[1], &A_val[ptr], len * sizeof(double));
+         for (t = 1; t <= len; t++) val[t] = - val[t];
+      }
+      return len;
+}
+
+static int invert_B(struct csa *csa)
+{     int ret;
+      ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa);
+      csa->valid = (ret == 0);
+      return ret;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  update_B - update factorization of the basis matrix
+*
+*  This routine replaces i-th column of the basis matrix B by k-th
+*  column of the augmented constraint matrix (I|-A) and then updates
+*  the factorization of B.
+*
+*  If the factorization has been successfully updated, the routine
+*  returns zero, otherwise non-zero. */
+
+static int update_B(struct csa *csa, int i, int k)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int ret;
+#ifdef GLP_DEBUG
+      xassert(1 <= i && i <= m);
+      xassert(1 <= k && k <= m+n);
+#endif
+      if (k <= m)
+      {  /* new i-th column of B is k-th column of I */
+         int ind[1+1];
+         double val[1+1];
+         ind[1] = k;
+         val[1] = 1.0;
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val);
+      }
+      else
+      {  /* new i-th column of B is (k-m)-th column of (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         double *val = csa->work1;
+         int beg, end, ptr, len;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         len = 0;
+         for (ptr = beg; ptr < end; ptr++)
+            val[++len] = - A_val[ptr];
+         xassert(csa->valid);
+         ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val);
+      }
+      csa->valid = (ret == 0);
+      return ret;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  error_ftran - compute residual vector r = h - B * x
+*
+*  This routine computes the residual vector r = h - B * x, where B is
+*  the current basis matrix, h is the vector of right-hand sides, x is
+*  the solution vector. */
+
+static void error_ftran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector:
+         r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m],
+         where B[1], ..., B[m] are columns of matrix B */
+      memcpy(&r[1], &h[1], m * sizeof(double));
+      for (i = 1; i <= m; i++)
+      {  temp = x[i];
+         if (temp == 0.0) continue;
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            r[k] -= temp;
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               r[A_ind[ptr]] += A_val[ptr] * temp;
+         }
+      }
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_ftran - refine solution of B * x = h
+*
+*  This routine performs one iteration to refine the solution of
+*  the system B * x = h, where B is the current basis matrix, h is the
+*  vector of right-hand sides, x is the solution vector. */
+
+static void refine_ftran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B * x */
+      error_ftran(csa, h, x, r);
+      /* compute the correction vector d = inv(B) * r */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  error_btran - compute residual vector r = h - B'* x
+*
+*  This routine computes the residual vector r = h - B'* x, where B'
+*  is a matrix transposed to the current basis matrix, h is the vector
+*  of right-hand sides, x is the solution vector. */
+
+static void error_btran(struct csa *csa, double h[], double x[],
+      double r[])
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      int i, k, beg, end, ptr;
+      double temp;
+      /* compute the residual vector r = b - B'* x */
+      for (i = 1; i <= m; i++)
+      {  /* r[i] := b[i] - (i-th column of B)'* x */
+         k = head[i]; /* B[i] is k-th column of (I|-A) */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         temp = h[i];
+         if (k <= m)
+         {  /* B[i] is k-th column of submatrix I */
+            temp -= x[k];
+         }
+         else
+         {  /* B[i] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               temp += A_val[ptr] * x[A_ind[ptr]];
+         }
+         r[i] = temp;
+      }
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_btran - refine solution of B'* x = h
+*
+*  This routine performs one iteration to refine the solution of the
+*  system B'* x = h, where B' is a matrix transposed to the current
+*  basis matrix, h is the vector of right-hand sides, x is the solution
+*  vector. */
+
+static void refine_btran(struct csa *csa, double h[], double x[])
+{     int m = csa->m;
+      double *r = csa->work1;
+      double *d = csa->work1;
+      int i;
+      /* compute the residual vector r = h - B'* x */
+      error_btran(csa, h, x, r);
+      /* compute the correction vector d = inv(B') * r */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, d);
+      /* refine the solution vector (new x) = (old x) + d */
+      for (i = 1; i <= m; i++) x[i] += d[i];
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  get_xN - determine current value of non-basic variable xN[j]
+*
+*  This routine returns the current value of non-basic variable xN[j],
+*  which is a value of its active bound. */
+
+static double get_xN(struct csa *csa, int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int k;
+      double xN;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      switch (stat[j])
+      {  case GLP_NL:
+            /* x[k] is on its lower bound */
+            xN = lb[k]; break;
+         case GLP_NU:
+            /* x[k] is on its upper bound */
+            xN = ub[k]; break;
+         case GLP_NF:
+            /* x[k] is free non-basic variable */
+            xN = 0.0; break;
+         case GLP_NS:
+            /* x[k] is fixed non-basic variable */
+            xN = lb[k]; break;
+         default:
+            xassert(stat != stat);
+      }
+      return xN;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_beta - compute primal values of basic variables
+*
+*  This routine computes current primal values of all basic variables:
+*
+*     beta = - inv(B) * N * xN,
+*
+*  where B is the current basis matrix, N is a matrix built of columns
+*  of matrix (I|-A) corresponding to non-basic variables, and xN is the
+*  vector of current values of non-basic variables. */
+
+static void eval_beta(struct csa *csa, double beta[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      double *h = csa->work2;
+      int i, j, k, beg, end, ptr;
+      double xN;
+      /* compute the right-hand side vector:
+         h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n],
+         where N[1], ..., N[n] are columns of matrix N */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* determine current value of xN[j] */
+         xN = get_xN(csa, j);
+         if (xN == 0.0) continue;
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            h[k] -= xN;
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               h[A_ind[ptr]] += xN * A_val[ptr];
+         }
+      }
+      /* solve system B * beta = h */
+      memcpy(&beta[1], &h[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, beta);
+      /* and refine the solution */
+      refine_ftran(csa, h, beta);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_pi - compute vector of simplex multipliers
+*
+*  This routine computes the vector of current simplex multipliers:
+*
+*     pi = inv(B') * cB,
+*
+*  where B' is a matrix transposed to the current basis matrix, cB is
+*  a subvector of objective coefficients at basic variables. */
+
+static void eval_pi(struct csa *csa, double pi[])
+{     int m = csa->m;
+      double *c = csa->coef;
+      int *head = csa->head;
+      double *cB = csa->work2;
+      int i;
+      /* construct the right-hand side vector cB */
+      for (i = 1; i <= m; i++)
+         cB[i] = c[head[i]];
+      /* solve system B'* pi = cB */
+      memcpy(&pi[1], &cB[1], m * sizeof(double));
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, pi);
+      /* and refine the solution */
+      refine_btran(csa, cB, pi);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_cost - compute reduced cost of non-basic variable xN[j]
+*
+*  This routine computes the current reduced cost of non-basic variable
+*  xN[j]:
+*
+*     d[j] = cN[j] - N'[j] * pi,
+*
+*  where cN[j] is the objective coefficient at variable xN[j], N[j] is
+*  a column of the augmented constraint matrix (I|-A) corresponding to
+*  xN[j], pi is the vector of simplex multipliers. */
+
+static double eval_cost(struct csa *csa, double pi[], int j)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *coef = csa->coef;
+      int *head = csa->head;
+      int k;
+      double dj;
+#ifdef GLP_DEBUG
+      xassert(1 <= j && j <= n);
+#endif
+      k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      dj = coef[k];
+      if (k <= m)
+      {  /* N[j] is k-th column of submatrix I */
+         dj -= pi[k];
+      }
+      else
+      {  /* N[j] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            dj += A_val[ptr] * pi[A_ind[ptr]];
+      }
+      return dj;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_bbar - compute and store primal values of basic variables
+*
+*  This routine computes primal values of all basic variables and then
+*  stores them in the solution array. */
+
+static void eval_bbar(struct csa *csa)
+{     eval_beta(csa, csa->bbar);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_cbar - compute and store reduced costs of non-basic variables
+*
+*  This routine computes reduced costs of all non-basic variables and
+*  then stores them in the solution array. */
+
+static void eval_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+#endif
+      int n = csa->n;
+#ifdef GLP_DEBUG
+      int *head = csa->head;
+#endif
+      double *cbar = csa->cbar;
+      double *pi = csa->work3;
+      int j;
+#ifdef GLP_DEBUG
+      int k;
+#endif
+      /* compute simplex multipliers */
+      eval_pi(csa, pi);
+      /* compute and store reduced costs */
+      for (j = 1; j <= n; j++)
+      {
+#ifdef GLP_DEBUG
+         k = head[m+j]; /* x[k] = xN[j] */
+         xassert(1 <= k && k <= m+n);
+#endif
+         cbar[j] = eval_cost(csa, pi, j);
+      }
+      return;
+}
+#endif
+
+/***********************************************************************
+*  reset_refsp - reset the reference space
+*
+*  This routine resets (redefines) the reference space used in the
+*  projected steepest edge pricing algorithm. */
+
+static void reset_refsp(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int i, k;
+      xassert(csa->refct == 0);
+      csa->refct = 1000;
+      memset(&refsp[1], 0, (m+n) * sizeof(char));
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+         refsp[k] = 1;
+         gamma[i] = 1.0;
+      }
+      return;
+}
+
+/***********************************************************************
+*  eval_gamma - compute steepest edge coefficients
+*
+*  This routine computes the vector of steepest edge coefficients for
+*  all basic variables (except free ones) using its direct definition:
+*
+*     gamma[i] = eta[i] +  sum   alfa[i,j]^2,  i = 1,...,m,
+*                         j in C
+*
+*  where eta[i] = 1 means that xB[i] is in the current reference space,
+*  and 0 otherwise; C is a set of non-basic non-fixed variables xN[j],
+*  which are in the current reference space; alfa[i,j] are elements of
+*  the current simplex table.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static void eval_gamma(struct csa *csa, double gamma[])
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *alfa = csa->work3;
+      double *h = csa->work3;
+      int i, j, k;
+      /* gamma[i] := eta[i] (or 1, if xB[i] is free) */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (type[k] == GLP_FR)
+            gamma[i] = 1.0;
+         else
+            gamma[i] = (refsp[k] ? 1.0 : 0.0);
+      }
+      /* compute columns of the current simplex table */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* skip column, if xN[j] is not in C */
+         if (!refsp[k]) continue;
+#ifdef GLP_DEBUG
+         /* set C must not contain fixed variables */
+         xassert(type[k] != GLP_FX);
+#endif
+         /* construct the right-hand side vector h = - N[j] */
+         for (i = 1; i <= m; i++)
+            h[i] = 0.0;
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            h[k] = -1.0;
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            int *A_ptr = csa->A_ptr;
+            int *A_ind = csa->A_ind;
+            double *A_val = csa->A_val;
+            int beg, end, ptr;
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               h[A_ind[ptr]] = A_val[ptr];
+         }
+         /* solve system B * alfa = h */
+         xassert(csa->valid);
+         bfd_ftran(csa->bfd, alfa);
+         /* gamma[i] := gamma[i] + alfa[i,j]^2 */
+         for (i = 1; i <= m; i++)
+         {  k = head[i]; /* x[k] = xB[i] */
+            if (type[k] != GLP_FR)
+               gamma[i] += alfa[i] * alfa[i];
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  chuzr - choose basic variable (row of the simplex table)
+*
+*  This routine chooses basic variable xB[p] having largest weighted
+*  bound violation:
+*
+*     |r[p]| / sqrt(gamma[p]) = max  |r[i]| / sqrt(gamma[i]),
+*                              i in I
+*
+*            / lB[i] - beta[i], if beta[i] < lB[i]
+*            |
+*     r[i] = < 0,               if lB[i] <= beta[i] <= uB[i]
+*            |
+*            \ uB[i] - beta[i], if beta[i] > uB[i]
+*
+*  where beta[i] is primal value of xB[i] in the current basis, lB[i]
+*  and uB[i] are lower and upper bounds of xB[i], I is a subset of
+*  eligible basic variables, which significantly violates their bounds,
+*  gamma[i] is the steepest edge coefficient.
+*
+*  If |r[i]| is less than a specified tolerance, xB[i] is not included
+*  in I and therefore ignored.
+*
+*  If I is empty and no variable has been chosen, p is set to 0. */
+
+static void chuzr(struct csa *csa, double tol_bnd)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      double *gamma = csa->gamma;
+      int i, k, p;
+      double delta, best, eps, ri, temp;
+      /* nothing is chosen so far */
+      p = 0, delta = 0.0, best = 0.0;
+      /* look through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* determine bound violation ri[i] */
+         ri = 0.0;
+         if (type[k] == GLP_LO || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* xB[i] has lower bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(lb[k]));
+            if (bbar[i] < lb[k] - eps)
+            {  /* and significantly violates it */
+               ri = lb[k] - bbar[i];
+            }
+         }
+         if (type[k] == GLP_UP || type[k] == GLP_DB ||
+             type[k] == GLP_FX)
+         {  /* xB[i] has upper bound */
+            eps = tol_bnd * (1.0 + kappa * fabs(ub[k]));
+            if (bbar[i] > ub[k] + eps)
+            {  /* and significantly violates it */
+               ri = ub[k] - bbar[i];
+            }
+         }
+         /* if xB[i] is not eligible, skip it */
+         if (ri == 0.0) continue;
+         /* xB[i] is eligible basic variable; choose one with largest
+            weighted bound violation */
+#ifdef GLP_DEBUG
+         xassert(gamma[i] >= 0.0);
+#endif
+         temp = gamma[i];
+         if (temp < DBL_EPSILON) temp = DBL_EPSILON;
+         temp = (ri * ri) / temp;
+         if (best < temp)
+            p = i, delta = ri, best = temp;
+      }
+      /* store the index of basic variable xB[p] chosen and its change
+         in the adjacent basis */
+      csa->p = p;
+      csa->delta = delta;
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_rho - compute pivot row of the inverse
+*
+*  This routine computes the pivot (p-th) row of the inverse inv(B),
+*  which corresponds to basic variable xB[p] chosen:
+*
+*     rho = inv(B') * e[p],
+*
+*  where B' is a matrix transposed to the current basis matrix, e[p]
+*  is unity vector. */
+
+static void eval_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = rho;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* solve system B'* rho = e[p] */
+      xassert(csa->valid);
+      bfd_btran(csa->bfd, rho);
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_rho - refine pivot row of the inverse
+*
+*  This routine refines the pivot row of the inverse inv(B) assuming
+*  that it was previously computed by the routine eval_rho. */
+
+static void refine_rho(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int p = csa->p;
+      double *e = csa->work3;
+      int i;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* construct the right-hand side vector e[p] */
+      for (i = 1; i <= m; i++)
+         e[i] = 0.0;
+      e[p] = 1.0;
+      /* refine solution of B'* rho = e[p] */
+      refine_btran(csa, e, rho);
+      return;
+}
+#endif
+
+#if 1 /* 06/IV-2009 */
+/***********************************************************************
+*  eval_trow - compute pivot row of the simplex table
+*
+*  This routine computes the pivot row of the simplex table, which
+*  corresponds to basic variable xB[p] chosen.
+*
+*  The pivot row is the following vector:
+*
+*     trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho,
+*
+*  where rho is the pivot row of the inverse inv(B) previously computed
+*  by the routine eval_rho.
+*
+*  Note that elements of the pivot row corresponding to fixed non-basic
+*  variables are not computed.
+*
+*  NOTES
+*
+*  Computing pivot row of the simplex table is one of the most time
+*  consuming operations, and for some instances it may take more than
+*  50% of the total solution time.
+*
+*  In the current implementation there are two routines to compute the
+*  pivot row. The routine eval_trow1 computes elements of the pivot row
+*  as inner products of columns of the matrix N and the vector rho; it
+*  is used when the vector rho is relatively dense. The routine
+*  eval_trow2 computes the pivot row as a linear combination of rows of
+*  the matrix N; it is used when the vector rho is relatively sparse. */
+
+static void eval_trow1(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *A_ptr = csa->A_ptr;
+      int *A_ind = csa->A_ind;
+      double *A_val = csa->A_val;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int j, k, beg, end, ptr, nnz;
+      double temp;
+      /* compute the pivot row as inner products of columns of the
+         matrix N and vector rho: trow[j] = - rho * N[j] */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS)
+         {  /* xN[j] is fixed */
+            trow_vec[j] = 0.0;
+            continue;
+         }
+         k = head[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+         {  /* N[j] is k-th column of submatrix I */
+            temp = - rho[k];
+         }
+         else
+         {  /* N[j] is (k-m)-th column of submatrix (-A) */
+            beg = A_ptr[k-m], end = A_ptr[k-m+1];
+            temp = 0.0;
+            for (ptr = beg; ptr < end; ptr++)
+               temp += rho[A_ind[ptr]] * A_val[ptr];
+         }
+         if (temp != 0.0)
+            trow_ind[++nnz] = j;
+         trow_vec[j] = temp;
+      }
+      csa->trow_nnz = nnz;
+      return;
+}
+
+static void eval_trow2(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int n = csa->n;
+      int *AT_ptr = csa->AT_ptr;
+      int *AT_ind = csa->AT_ind;
+      double *AT_val = csa->AT_val;
+      int *bind = csa->bind;
+      char *stat = csa->stat;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int i, j, beg, end, ptr, nnz;
+      double temp;
+      /* clear the pivot row */
+      for (j = 1; j <= n; j++)
+         trow_vec[j] = 0.0;
+      /* compute the pivot row as a linear combination of rows of the
+         matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */
+      for (i = 1; i <= m; i++)
+      {  temp = rho[i];
+         if (temp == 0.0) continue;
+         /* trow := trow - rho[i] * N'[i] */
+         j = bind[i] - m; /* x[i] = xN[j] */
+         if (j >= 1 && stat[j] != GLP_NS)
+            trow_vec[j] -= temp;
+         beg = AT_ptr[i], end = AT_ptr[i+1];
+         for (ptr = beg; ptr < end; ptr++)
+         {  j = bind[m + AT_ind[ptr]] - m; /* x[k] = xN[j] */
+            if (j >= 1 && stat[j] != GLP_NS)
+               trow_vec[j] += temp * AT_val[ptr];
+         }
+      }
+      /* construct sparse pattern of the pivot row */
+      nnz = 0;
+      for (j = 1; j <= n; j++)
+      {  if (trow_vec[j] != 0.0)
+            trow_ind[++nnz] = j;
+      }
+      csa->trow_nnz = nnz;
+      return;
+}
+
+static void eval_trow(struct csa *csa, double rho[])
+{     int m = csa->m;
+      int i, nnz;
+      double dens;
+      /* determine the density of the vector rho */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+         if (rho[i] != 0.0) nnz++;
+      dens = (double)nnz / (double)m;
+      if (dens >= 0.20)
+      {  /* rho is relatively dense */
+         eval_trow1(csa, rho);
+      }
+      else
+      {  /* rho is relatively sparse */
+         eval_trow2(csa, rho);
+      }
+      return;
+}
+#endif
+
+/***********************************************************************
+*  sort_trow - sort pivot row of the simplex table
+*
+*  This routine reorders the list of non-zero elements of the pivot
+*  row to put significant elements, whose magnitude is not less than
+*  a specified tolerance, in front of the list, and stores the number
+*  of significant elements in trow_num. */
+
+static void sort_trow(struct csa *csa, double tol_piv)
+{
+#ifdef GLP_DEBUG
+      int n = csa->n;
+      char *stat = csa->stat;
+#endif
+      int nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int j, num, pos;
+      double big, eps, temp;
+      /* compute infinity (maximum) norm of the row */
+      big = 0.0;
+      for (pos = 1; pos <= nnz; pos++)
+      {
+#ifdef GLP_DEBUG
+         j = trow_ind[pos];
+         xassert(1 <= j && j <= n);
+         xassert(stat[j] != GLP_NS);
+#endif
+         temp = fabs(trow_vec[trow_ind[pos]]);
+         if (big < temp) big = temp;
+      }
+      csa->trow_max = big;
+      /* determine absolute pivot tolerance */
+      eps = tol_piv * (1.0 + 0.01 * big);
+      /* move significant row components to the front of the list */
+      for (num = 0; num < nnz; )
+      {  j = trow_ind[nnz];
+         if (fabs(trow_vec[j]) < eps)
+            nnz--;
+         else
+         {  num++;
+            trow_ind[nnz] = trow_ind[num];
+            trow_ind[num] = j;
+         }
+      }
+      csa->trow_num = num;
+      return;
+}
+
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+static int ls_func(const void *p1_, const void *p2_)
+{     const struct bkpt *p1 = p1_, *p2 = p2_;
+      if (p1->t < p2->t) return -1;
+      if (p1->t > p2->t) return +1;
+      return 0;
+}
+
+static int ls_func1(const void *p1_, const void *p2_)
+{     const struct bkpt *p1 = p1_, *p2 = p2_;
+      if (p1->dz < p2->dz) return -1;
+      if (p1->dz > p2->dz) return +1;
+      return 0;
+}
+
+static void long_step(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      double delta = csa->delta;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int trow_num = csa->trow_num;
+      struct bkpt *bkpt = csa->bkpt;
+      int j, k, kk, nbps, pos;
+      double alfa, s, slope, dzmax;
+      /* delta > 0 means that xB[p] violates its lower bound, so to
+         increase the dual objective lambdaB[p] must increase;
+         delta < 0 means that xB[p] violates its upper bound, so to
+         increase the dual objective lambdaB[p] must decrease */
+      /* s := sign(delta) */
+      s = (delta > 0.0 ? +1.0 : -1.0);
+      /* determine breakpoints of the dual objective */
+      nbps = 0;
+      for (pos = 1; pos <= trow_num; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+         xassert(stat[j] != GLP_NS);
+#endif
+         /* if there is free non-basic variable, switch to the standard
+            ratio test */
+         if (stat[j] == GLP_NF)
+         {  nbps = 0;
+            goto done;
+         }
+         /* lambdaN[j] = ... - alfa * t - ..., where t = s * lambdaB[i]
+            is the dual ray parameter, t >= 0 */
+         alfa = s * trow_vec[j];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+         xassert(stat[j] == GLP_NL || stat[j] == GLP_NU);
+#endif
+         if (alfa > 0.0 && stat[j] == GLP_NL ||
+             alfa < 0.0 && stat[j] == GLP_NU)
+         {  /* either lambdaN[j] >= 0 (if stat = GLP_NL) and decreases
+               or lambdaN[j] <= 0 (if stat = GLP_NU) and increases; in
+               both cases we have a breakpoint */
+            nbps++;
+#ifdef GLP_DEBUG
+            xassert(nbps <= n);
+#endif
+            bkpt[nbps].j = j;
+            bkpt[nbps].t = cbar[j] / alfa;
+/*
+if (stat[j] == GLP_NL && cbar[j] < 0.0 ||
+    stat[j] == GLP_NU && cbar[j] > 0.0)
+xprintf("%d %g\n", stat[j], cbar[j]);
+*/
+            /* if t is negative, replace it by exact zero (see comments
+               in the routine chuzc) */
+            if (bkpt[nbps].t < 0.0) bkpt[nbps].t = 0.0;
+         }
+      }
+      /* if there are less than two breakpoints, switch to the standard
+         ratio test */
+      if (nbps < 2)
+      {  nbps = 0;
+         goto done;
+      }
+      /* sort breakpoints by ascending the dual ray parameter, t */
+      qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func);
+      /* determine last breakpoint, at which the dual objective still
+         greater than at t = 0 */
+      dzmax = 0.0;
+      slope = fabs(delta); /* initial slope */
+      for (kk = 1; kk <= nbps; kk++)
+      {  if (kk == 1)
+            bkpt[kk].dz =
+               0.0 + slope * (bkpt[kk].t - 0.0);
+         else
+            bkpt[kk].dz =
+               bkpt[kk-1].dz + slope * (bkpt[kk].t - bkpt[kk-1].t);
+         if (dzmax < bkpt[kk].dz)
+            dzmax = bkpt[kk].dz;
+         else if (bkpt[kk].dz < 0.05 * (1.0 + dzmax))
+         {  nbps = kk - 1;
+            break;
+         }
+         j = bkpt[kk].j;
+         k = head[m+j]; /* x[k] = xN[j] */
+         if (type[k] == GLP_DB)
+            slope -= fabs(trow_vec[j]) * (ub[k] - lb[k]);
+         else
+         {  nbps = kk;
+            break;
+         }
+      }
+      /* if there are less than two breakpoints, switch to the standard
+         ratio test */
+      if (nbps < 2)
+      {  nbps = 0;
+         goto done;
+      }
+      /* sort breakpoints by ascending the dual change, dz */
+      qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func1);
+/*
+for (kk = 1; kk <= nbps; kk++)
+xprintf("%d; t = %g; dz = %g\n", kk, bkpt[kk].t, bkpt[kk].dz);
+*/
+done: csa->nbps = nbps;
+      return;
+}
+#endif
+
+/***********************************************************************
+*  chuzc - choose non-basic variable (column of the simplex table)
+*
+*  This routine chooses non-basic variable xN[q], which being entered
+*  in the basis keeps dual feasibility of the basic solution.
+*
+*  The parameter rtol is a relative tolerance used to relax zero bounds
+*  of reduced costs of non-basic variables. If rtol = 0, the routine
+*  implements the standard ratio test. Otherwise, if rtol > 0, the
+*  routine implements Harris' two-pass ratio test. In the latter case
+*  rtol should be about three times less than a tolerance used to check
+*  dual feasibility. */
+
+static void chuzc(struct csa *csa, double rtol)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+      int n = csa->n;
+#endif
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+#ifdef GLP_DEBUG
+      int p = csa->p;
+#endif
+      double delta = csa->delta;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int trow_num = csa->trow_num;
+      int j, pos, q;
+      double alfa, big, s, t, teta, tmax;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+#endif
+      /* delta > 0 means that xB[p] violates its lower bound and goes
+         to it in the adjacent basis, so lambdaB[p] is increasing from
+         its lower zero bound;
+         delta < 0 means that xB[p] violates its upper bound and goes
+         to it in the adjacent basis, so lambdaB[p] is decreasing from
+         its upper zero bound */
+#ifdef GLP_DEBUG
+      xassert(delta != 0.0);
+#endif
+      /* s := sign(delta) */
+      s = (delta > 0.0 ? +1.0 : -1.0);
+      /*** FIRST PASS ***/
+      /* nothing is chosen so far */
+      q = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through significant elements of the pivot row */
+      for (pos = 1; pos <= trow_num; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         alfa = s * trow_vec[j];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
+            need to consider only increasing lambdaB[p] */
+         if (alfa > 0.0)
+         {  /* lambdaN[j] is decreasing */
+            if (stat[j] == GLP_NL || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero lower bound */
+               t = (cbar[j] + rtol) / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no lower bound */
+               continue;
+            }
+         }
+         else
+         {  /* lambdaN[j] is increasing */
+            if (stat[j] == GLP_NU || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero upper bound */
+               t = (cbar[j] - rtol) / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no upper bound */
+               continue;
+            }
+         }
+         /* t is a change of lambdaB[p], on which lambdaN[j] reaches
+            its zero bound (possibly relaxed); since the basic solution
+            is assumed to be dual feasible, t has to be non-negative by
+            definition; however, it may happen that lambdaN[j] slightly
+            (i.e. within a tolerance) violates its zero bound, that
+            leads to negative t; in the latter case, if xN[j] is chosen,
+            negative t means that lambdaB[p] changes in wrong direction
+            that may cause wrong results on updating reduced costs;
+            thus, if t is negative, we should replace it by exact zero
+            assuming that lambdaN[j] is exactly on its zero bound, and
+            violation appears due to round-off errors */
+         if (t < 0.0) t = 0.0;
+         /* apply minimal ratio test */
+         if (teta > t || teta == t && big < fabs(alfa))
+            q = j, teta = t, big = fabs(alfa);
+      }
+      /* the second pass is skipped in the following cases: */
+      /* if the standard ratio test is used */
+      if (rtol == 0.0) goto done;
+      /* if no non-basic variable has been chosen on the first pass */
+      if (q == 0) goto done;
+      /* if lambdaN[q] prevents lambdaB[p] from any change */
+      if (teta == 0.0) goto done;
+      /*** SECOND PASS ***/
+      /* here tmax is a maximal change of lambdaB[p], on which the
+         solution remains dual feasible within a tolerance */
+#if 0
+      tmax = (1.0 + 10.0 * DBL_EPSILON) * teta;
+#else
+      tmax = teta;
+#endif
+      /* nothing is chosen so far */
+      q = 0, teta = DBL_MAX, big = 0.0;
+      /* walk through significant elements of the pivot row */
+      for (pos = 1; pos <= trow_num; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         alfa = s * trow_vec[j];
+#ifdef GLP_DEBUG
+         xassert(alfa != 0.0);
+#endif
+         /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we
+            need to consider only increasing lambdaB[p] */
+         if (alfa > 0.0)
+         {  /* lambdaN[j] is decreasing */
+            if (stat[j] == GLP_NL || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero lower bound */
+               t = cbar[j] / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no lower bound */
+               continue;
+            }
+         }
+         else
+         {  /* lambdaN[j] is increasing */
+            if (stat[j] == GLP_NU || stat[j] == GLP_NF)
+            {  /* lambdaN[j] has zero upper bound */
+               t = cbar[j] / alfa;
+            }
+            else
+            {  /* lambdaN[j] has no upper bound */
+               continue;
+            }
+         }
+         /* (see comments for the first pass) */
+         if (t < 0.0) t = 0.0;
+         /* t is a change of lambdaB[p], on which lambdaN[j] reaches
+            its zero (lower or upper) bound; if t <= tmax, all reduced
+            costs can violate their zero bounds only within relaxation
+            tolerance rtol, so we can choose non-basic variable having
+            largest influence coefficient to avoid possible numerical
+            instability */
+         if (t <= tmax && big < fabs(alfa))
+            q = j, teta = t, big = fabs(alfa);
+      }
+      /* something must be chosen on the second pass */
+      xassert(q != 0);
+done: /* store the index of non-basic variable xN[q] chosen */
+      csa->q = q;
+      /* store reduced cost of xN[q] in the adjacent basis */
+      csa->new_dq = s * teta;
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_tcol - compute pivot column of the simplex table
+*
+*  This routine computes the pivot column of the simplex table, which
+*  corresponds to non-basic variable xN[q] chosen.
+*
+*  The pivot column is the following vector:
+*
+*     tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],
+*
+*  where B is the current basis matrix, N[q] is a column of the matrix
+*  (I|-A) corresponding to variable xN[q]. */
+
+static void eval_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->tcol_vec;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* solve system B * tcol = h */
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  refine_tcol - refine pivot column of the simplex table
+*
+*  This routine refines the pivot column of the simplex table assuming
+*  that it was previously computed by the routine eval_tcol. */
+
+static void refine_tcol(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      int *head = csa->head;
+      int q = csa->q;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *h = csa->work3;
+      int i, k, nnz;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      k = head[m+q]; /* x[k] = xN[q] */
+#ifdef GLP_DEBUG
+      xassert(1 <= k && k <= m+n);
+#endif
+      /* construct the right-hand side vector h = - N[q] */
+      for (i = 1; i <= m; i++)
+         h[i] = 0.0;
+      if (k <= m)
+      {  /* N[q] is k-th column of submatrix I */
+         h[k] = -1.0;
+      }
+      else
+      {  /* N[q] is (k-m)-th column of submatrix (-A) */
+         int *A_ptr = csa->A_ptr;
+         int *A_ind = csa->A_ind;
+         double *A_val = csa->A_val;
+         int beg, end, ptr;
+         beg = A_ptr[k-m];
+         end = A_ptr[k-m+1];
+         for (ptr = beg; ptr < end; ptr++)
+            h[A_ind[ptr]] = A_val[ptr];
+      }
+      /* refine solution of B * tcol = h */
+      refine_ftran(csa, h, tcol_vec);
+      /* construct sparse pattern of the pivot column */
+      nnz = 0;
+      for (i = 1; i <= m; i++)
+      {  if (tcol_vec[i] != 0.0)
+            tcol_ind[++nnz] = i;
+      }
+      csa->tcol_nnz = nnz;
+      return;
+}
+#endif
+
+/***********************************************************************
+*  update_cbar - update reduced costs of non-basic variables
+*
+*  This routine updates reduced costs of all (except fixed) non-basic
+*  variables for the adjacent basis. */
+
+static void update_cbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      double *cbar = csa->cbar;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int q = csa->q;
+      double new_dq = csa->new_dq;
+      int j, pos;
+#ifdef GLP_DEBUG
+      xassert(1 <= q && q <= n);
+#endif
+      /* set new reduced cost of xN[q] */
+      cbar[q] = new_dq;
+      /* update reduced costs of other non-basic variables */
+      if (new_dq == 0.0) goto done;
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         if (j != q)
+            cbar[j] -= trow_vec[j] * new_dq;
+      }
+done: return;
+}
+
+/***********************************************************************
+*  update_bbar - update values of basic variables
+*
+*  This routine updates values of all basic variables for the adjacent
+*  basis. */
+
+static void update_bbar(struct csa *csa)
+{
+#ifdef GLP_DEBUG
+      int m = csa->m;
+      int n = csa->n;
+#endif
+      double *bbar = csa->bbar;
+      int p = csa->p;
+      double delta = csa->delta;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      int i, pos;
+      double teta;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* determine the change of xN[q] in the adjacent basis */
+#ifdef GLP_DEBUG
+      xassert(tcol_vec[p] != 0.0);
+#endif
+      teta = delta / tcol_vec[p];
+      /* set new primal value of xN[q] */
+      bbar[p] = get_xN(csa, q) + teta;
+      /* update primal values of other basic variables */
+      if (teta == 0.0) goto done;
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         if (i != p)
+            bbar[i] += tcol_vec[i] * teta;
+      }
+done: return;
+}
+
+/***********************************************************************
+*  update_gamma - update steepest edge coefficients
+*
+*  This routine updates steepest-edge coefficients for the adjacent
+*  basis. */
+
+static void update_gamma(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      int *head = csa->head;
+      char *refsp = csa->refsp;
+      double *gamma = csa->gamma;
+      int p = csa->p;
+      int trow_nnz = csa->trow_nnz;
+      int *trow_ind = csa->trow_ind;
+      double *trow_vec = csa->trow_vec;
+      int q = csa->q;
+      int tcol_nnz = csa->tcol_nnz;
+      int *tcol_ind = csa->tcol_ind;
+      double *tcol_vec = csa->tcol_vec;
+      double *u = csa->work3;
+      int i, j, k,pos;
+      double gamma_p, eta_p, pivot, t, t1, t2;
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* the basis changes, so decrease the count */
+      xassert(csa->refct > 0);
+      csa->refct--;
+      /* recompute gamma[p] for the current basis more accurately and
+         compute auxiliary vector u */
+#ifdef GLP_DEBUG
+      xassert(type[head[p]] != GLP_FR);
+#endif
+      gamma_p = eta_p = (refsp[head[p]] ? 1.0 : 0.0);
+      for (i = 1; i <= m; i++) u[i] = 0.0;
+      for (pos = 1; pos <= trow_nnz; pos++)
+      {  j = trow_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= j && j <= n);
+#endif
+         k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+         xassert(type[k] != GLP_FX);
+#endif
+         if (!refsp[k]) continue;
+         t = trow_vec[j];
+         gamma_p += t * t;
+         /* u := u + N[j] * delta[j] * trow[j] */
+         if (k <= m)
+         {  /* N[k] = k-j stolbec submatrix I */
+            u[k] += t;
+         }
+         else
+         {  /* N[k] = k-m-k stolbec (-A) */
+            int *A_ptr = csa->A_ptr;
+            int *A_ind = csa->A_ind;
+            double *A_val = csa->A_val;
+            int beg, end, ptr;
+            beg = A_ptr[k-m];
+            end = A_ptr[k-m+1];
+            for (ptr = beg; ptr < end; ptr++)
+               u[A_ind[ptr]] -= t * A_val[ptr];
+         }
+      }
+      xassert(csa->valid);
+      bfd_ftran(csa->bfd, u);
+      /* update gamma[i] for other basic variables (except xB[p] and
+         free variables) */
+      pivot = tcol_vec[p];
+#ifdef GLP_DEBUG
+      xassert(pivot != 0.0);
+#endif
+      for (pos = 1; pos <= tcol_nnz; pos++)
+      {  i = tcol_ind[pos];
+#ifdef GLP_DEBUG
+         xassert(1 <= i && i <= m);
+#endif
+         k = head[i];
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         /* skip xB[p] */
+         if (i == p) continue;
+         /* skip free basic variable */
+         if (type[head[i]] == GLP_FR)
+         {
+#ifdef GLP_DEBUG
+            xassert(gamma[i] == 1.0);
+#endif
+            continue;
+         }
+         /* compute gamma[i] for the adjacent basis */
+         t = tcol_vec[i] / pivot;
+         t1 = gamma[i] + t * t * gamma_p + 2.0 * t * u[i];
+         t2 = (refsp[k] ? 1.0 : 0.0) + eta_p * t * t;
+         gamma[i] = (t1 >= t2 ? t1 : t2);
+         /* (though gamma[i] can be exact zero, because the reference
+            space does not include non-basic fixed variables) */
+         if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
+      }
+      /* compute gamma[p] for the adjacent basis */
+      if (type[head[m+q]] == GLP_FR)
+         gamma[p] = 1.0;
+      else
+      {  gamma[p] = gamma_p / (pivot * pivot);
+         if (gamma[p] < DBL_EPSILON) gamma[p] = DBL_EPSILON;
+      }
+      /* if xB[p], which becomes xN[q] in the adjacent basis, is fixed
+         and belongs to the reference space, remove it from there, and
+         change all gamma's appropriately */
+      k = head[p];
+      if (type[k] == GLP_FX && refsp[k])
+      {  refsp[k] = 0;
+         for (pos = 1; pos <= tcol_nnz; pos++)
+         {  i = tcol_ind[pos];
+            if (i == p)
+            {  if (type[head[m+q]] == GLP_FR) continue;
+               t = 1.0 / tcol_vec[p];
+            }
+            else
+            {  if (type[head[i]] == GLP_FR) continue;
+               t = tcol_vec[i] / tcol_vec[p];
+            }
+            gamma[i] -= t * t;
+            if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON;
+         }
+      }
+      return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  err_in_bbar - compute maximal relative error in primal solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |beta[i] - bbar[i]| / (1 + |beta[i]|),
+*
+*  where beta and bbar are, respectively, directly computed and the
+*  current (updated) values of basic variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_bbar(struct csa *csa)
+{     int m = csa->m;
+      double *bbar = csa->bbar;
+      int i;
+      double e, emax, *beta;
+      beta = xcalloc(1+m, sizeof(double));
+      eval_beta(csa, beta);
+      emax = 0.0;
+      for (i = 1; i <= m; i++)
+      {  e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i]));
+         if (emax < e) emax = e;
+      }
+      xfree(beta);
+      return emax;
+}
+#endif
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  err_in_cbar - compute maximal relative error in dual solution
+*
+*  This routine returns maximal relative error:
+*
+*     max |cost[j] - cbar[j]| / (1 + |cost[j]|),
+*
+*  where cost and cbar are, respectively, directly computed and the
+*  current (updated) reduced costs of non-basic non-fixed variables.
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_cbar(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j;
+      double e, emax, cost, *pi;
+      pi = xcalloc(1+m, sizeof(double));
+      eval_pi(csa, pi);
+      emax = 0.0;
+      for (j = 1; j <= n; j++)
+      {  if (stat[j] == GLP_NS) continue;
+         cost = eval_cost(csa, pi, j);
+         e = fabs(cost - cbar[j]) / (1.0 + fabs(cost));
+         if (emax < e) emax = e;
+      }
+      xfree(pi);
+      return emax;
+}
+#endif
+
+/***********************************************************************
+*  err_in_gamma - compute maximal relative error in steepest edge cff.
+*
+*  This routine returns maximal relative error:
+*
+*     max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]),
+*
+*  where gamma'[j] and gamma[j] are, respectively, directly computed
+*  and the current (updated) steepest edge coefficients for non-basic
+*  non-fixed variable x[j].
+*
+*  NOTE: The routine is intended only for debugginig purposes. */
+
+static double err_in_gamma(struct csa *csa)
+{     int m = csa->m;
+      char *type = csa->type;
+      int *head = csa->head;
+      double *gamma = csa->gamma;
+      double *exact = csa->work4;
+      int i;
+      double e, emax, temp;
+      eval_gamma(csa, exact);
+      emax = 0.0;
+      for (i = 1; i <= m; i++)
+      {  if (type[head[i]] == GLP_FR)
+         {  xassert(gamma[i] == 1.0);
+            xassert(exact[i] == 1.0);
+            continue;
+         }
+         temp = exact[i];
+         e = fabs(temp - gamma[i]) / (1.0 + fabs(temp));
+         if (emax < e) emax = e;
+      }
+      return emax;
+}
+
+/***********************************************************************
+*  change_basis - change basis header
+*
+*  This routine changes the basis header to make it corresponding to
+*  the adjacent basis. */
+
+static void change_basis(struct csa *csa)
+{     int m = csa->m;
+#ifdef GLP_DEBUG
+      int n = csa->n;
+#endif
+      char *type = csa->type;
+      int *head = csa->head;
+#if 1 /* 06/IV-2009 */
+      int *bind = csa->bind;
+#endif
+      char *stat = csa->stat;
+      int p = csa->p;
+      double delta = csa->delta;
+      int q = csa->q;
+      int k;
+      /* xB[p] leaves the basis, xN[q] enters the basis */
+#ifdef GLP_DEBUG
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+#endif
+      /* xB[p] <-> xN[q] */
+      k = head[p], head[p] = head[m+q], head[m+q] = k;
+#if 1 /* 06/IV-2009 */
+      bind[head[p]] = p, bind[head[m+q]] = m + q;
+#endif
+      if (type[k] == GLP_FX)
+         stat[q] = GLP_NS;
+      else if (delta > 0.0)
+      {
+#ifdef GLP_DEBUG
+         xassert(type[k] == GLP_LO || type[k] == GLP_DB);
+#endif
+         stat[q] = GLP_NL;
+      }
+      else /* delta < 0.0 */
+      {
+#ifdef GLP_DEBUG
+         xassert(type[k] == GLP_UP || type[k] == GLP_DB);
+#endif
+         stat[q] = GLP_NU;
+      }
+      return;
+}
+
+/***********************************************************************
+*  check_feas - check dual feasibility of basic solution
+*
+*  If the current basic solution is dual feasible within a tolerance,
+*  this routine returns zero, otherwise it returns non-zero. */
+
+static int check_feas(struct csa *csa, double tol_dj)
+{     int m = csa->m;
+      int n = csa->n;
+      char *orig_type = csa->orig_type;
+      int *head = csa->head;
+      double *cbar = csa->cbar;
+      int j, k;
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (cbar[j] < - tol_dj)
+            if (orig_type[k] == GLP_LO || orig_type[k] == GLP_FR)
+               return 1;
+         if (cbar[j] > + tol_dj)
+            if (orig_type[k] == GLP_UP || orig_type[k] == GLP_FR)
+               return 1;
+      }
+      return 0;
+}
+
+/***********************************************************************
+*  set_aux_bnds - assign auxiliary bounds to variables
+*
+*  This routine assigns auxiliary bounds to variables to construct an
+*  LP problem solved on phase I. */
+
+static void set_aux_bnds(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      char *orig_type = csa->orig_type;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j, k;
+      for (k = 1; k <= m+n; k++)
+      {  switch (orig_type[k])
+         {  case GLP_FR:
+#if 0
+               type[k] = GLP_DB, lb[k] = -1.0, ub[k] = +1.0;
+#else
+               /* to force free variables to enter the basis */
+               type[k] = GLP_DB, lb[k] = -1e3, ub[k] = +1e3;
+#endif
+               break;
+            case GLP_LO:
+               type[k] = GLP_DB, lb[k] = 0.0, ub[k] = +1.0;
+               break;
+            case GLP_UP:
+               type[k] = GLP_DB, lb[k] = -1.0, ub[k] = 0.0;
+               break;
+            case GLP_DB:
+            case GLP_FX:
+               type[k] = GLP_FX, lb[k] = ub[k] = 0.0;
+               break;
+            default:
+               xassert(orig_type != orig_type);
+         }
+      }
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (type[k] == GLP_FX)
+            stat[j] = GLP_NS;
+         else if (cbar[j] >= 0.0)
+            stat[j] = GLP_NL;
+         else
+            stat[j] = GLP_NU;
+      }
+      return;
+}
+
+/***********************************************************************
+*  set_orig_bnds - restore original bounds of variables
+*
+*  This routine restores original types and bounds of variables and
+*  determines statuses of non-basic variables assuming that the current
+*  basis is dual feasible. */
+
+static void set_orig_bnds(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      char *type = csa->type;
+      double *lb = csa->lb;
+      double *ub = csa->ub;
+      char *orig_type = csa->orig_type;
+      double *orig_lb = csa->orig_lb;
+      double *orig_ub = csa->orig_ub;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j, k;
+      memcpy(&type[1], &orig_type[1], (m+n) * sizeof(char));
+      memcpy(&lb[1], &orig_lb[1], (m+n) * sizeof(double));
+      memcpy(&ub[1], &orig_ub[1], (m+n) * sizeof(double));
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         switch (type[k])
+         {  case GLP_FR:
+               stat[j] = GLP_NF;
+               break;
+            case GLP_LO:
+               stat[j] = GLP_NL;
+               break;
+            case GLP_UP:
+               stat[j] = GLP_NU;
+               break;
+            case GLP_DB:
+               if (cbar[j] >= +DBL_EPSILON)
+                  stat[j] = GLP_NL;
+               else if (cbar[j] <= -DBL_EPSILON)
+                  stat[j] = GLP_NU;
+               else if (fabs(lb[k]) <= fabs(ub[k]))
+                  stat[j] = GLP_NL;
+               else
+                  stat[j] = GLP_NU;
+               break;
+            case GLP_FX:
+               stat[j] = GLP_NS;
+               break;
+            default:
+               xassert(type != type);
+         }
+      }
+      return;
+}
+
+/***********************************************************************
+*  check_stab - check numerical stability of basic solution
+*
+*  If the current basic solution is dual feasible within a tolerance,
+*  this routine returns zero, otherwise it returns non-zero. */
+
+static int check_stab(struct csa *csa, double tol_dj)
+{     int n = csa->n;
+      char *stat = csa->stat;
+      double *cbar = csa->cbar;
+      int j;
+      for (j = 1; j <= n; j++)
+      {  if (cbar[j] < - tol_dj)
+            if (stat[j] == GLP_NL || stat[j] == GLP_NF) return 1;
+         if (cbar[j] > + tol_dj)
+            if (stat[j] == GLP_NU || stat[j] == GLP_NF) return 1;
+      }
+      return 0;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  eval_obj - compute original objective function
+*
+*  This routine computes the current value of the original objective
+*  function. */
+
+static double eval_obj(struct csa *csa)
+{     int m = csa->m;
+      int n = csa->n;
+      double *obj = csa->obj;
+      int *head = csa->head;
+      double *bbar = csa->bbar;
+      int i, j, k;
+      double sum;
+      sum = obj[0];
+      /* walk through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * bbar[i];
+      }
+      /* walk through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k > m)
+            sum += obj[k-m] * get_xN(csa, j);
+      }
+      return sum;
+}
+#endif
+
+/***********************************************************************
+*  display - display the search progress
+*
+*  This routine displays some information about the search progress. */
+
+static void display(struct csa *csa, const glp_smcp *parm, int spec)
+{     int m = csa->m;
+      int n = csa->n;
+      double *coef = csa->coef;
+      char *orig_type = csa->orig_type;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      int phase = csa->phase;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int i, j, cnt;
+      double sum;
+      if (parm->msg_lev < GLP_MSG_ON) goto skip;
+      if (parm->out_dly > 0 &&
+         1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly)
+         goto skip;
+      if (csa->it_cnt == csa->it_dpy) goto skip;
+      if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip;
+      /* compute the sum of dual infeasibilities */
+      sum = 0.0;
+      if (phase == 1)
+      {  for (i = 1; i <= m; i++)
+            sum -= coef[head[i]] * bbar[i];
+         for (j = 1; j <= n; j++)
+            sum -= coef[head[m+j]] * get_xN(csa, j);
+      }
+      else
+      {  for (j = 1; j <= n; j++)
+         {  if (cbar[j] < 0.0)
+               if (stat[j] == GLP_NL || stat[j] == GLP_NF)
+                  sum -= cbar[j];
+            if (cbar[j] > 0.0)
+               if (stat[j] == GLP_NU || stat[j] == GLP_NF)
+                  sum += cbar[j];
+         }
+      }
+      /* determine the number of basic fixed variables */
+      cnt = 0;
+      for (i = 1; i <= m; i++)
+         if (orig_type[head[i]] == GLP_FX) cnt++;
+      if (csa->phase == 1)
+         xprintf(" %6d: %24s infeas = %10.3e (%d)\n",
+            csa->it_cnt, "", sum, cnt);
+      else
+         xprintf("|%6d: obj = %17.9e  infeas = %10.3e (%d)\n",
+            csa->it_cnt, eval_obj(csa), sum, cnt);
+      csa->it_dpy = csa->it_cnt;
+skip: return;
+}
+
+#if 1 /* copied from primal */
+/***********************************************************************
+*  store_sol - store basic solution back to the problem object
+*
+*  This routine stores basic solution components back to the problem
+*  object. */
+
+static void store_sol(struct csa *csa, glp_prob *lp, int p_stat,
+      int d_stat, int ray)
+{     int m = csa->m;
+      int n = csa->n;
+      double zeta = csa->zeta;
+      int *head = csa->head;
+      char *stat = csa->stat;
+      double *bbar = csa->bbar;
+      double *cbar = csa->cbar;
+      int i, j, k;
+#ifdef GLP_DEBUG
+      xassert(lp->m == m);
+      xassert(lp->n == n);
+#endif
+      /* basis factorization */
+#ifdef GLP_DEBUG
+      xassert(!lp->valid && lp->bfd == NULL);
+      xassert(csa->valid && csa->bfd != NULL);
+#endif
+      lp->valid = 1, csa->valid = 0;
+      lp->bfd = csa->bfd, csa->bfd = NULL;
+      memcpy(&lp->head[1], &head[1], m * sizeof(int));
+      /* basic solution status */
+      lp->pbs_stat = p_stat;
+      lp->dbs_stat = d_stat;
+      /* objective function value */
+      lp->obj_val = eval_obj(csa);
+      /* simplex iteration count */
+      lp->it_cnt = csa->it_cnt;
+      /* unbounded ray */
+      lp->some = ray;
+      /* basic variables */
+      for (i = 1; i <= m; i++)
+      {  k = head[i]; /* x[k] = xB[i] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = GLP_BS;
+            row->bind = i;
+            row->prim = bbar[i] / row->rii;
+            row->dual = 0.0;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = GLP_BS;
+            col->bind = i;
+            col->prim = bbar[i] * col->sjj;
+            col->dual = 0.0;
+         }
+      }
+      /* non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = head[m+j]; /* x[k] = xN[j] */
+#ifdef GLP_DEBUG
+         xassert(1 <= k && k <= m+n);
+#endif
+         if (k <= m)
+         {  GLPROW *row = lp->row[k];
+            row->stat = stat[j];
+            row->bind = 0;
+#if 0
+            row->prim = get_xN(csa, j) / row->rii;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  row->prim = row->lb; break;
+               case GLP_NU:
+                  row->prim = row->ub; break;
+               case GLP_NF:
+                  row->prim = 0.0; break;
+               case GLP_NS:
+                  row->prim = row->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            row->dual = (cbar[j] * row->rii) / zeta;
+         }
+         else
+         {  GLPCOL *col = lp->col[k-m];
+            col->stat = stat[j];
+            col->bind = 0;
+#if 0
+            col->prim = get_xN(csa, j) * col->sjj;
+#else
+            switch (stat[j])
+            {  case GLP_NL:
+                  col->prim = col->lb; break;
+               case GLP_NU:
+                  col->prim = col->ub; break;
+               case GLP_NF:
+                  col->prim = 0.0; break;
+               case GLP_NS:
+                  col->prim = col->lb; break;
+               default:
+                  xassert(stat != stat);
+            }
+#endif
+            col->dual = (cbar[j] / col->sjj) / zeta;
+         }
+      }
+      return;
+}
+#endif
+
+/***********************************************************************
+*  free_csa - deallocate common storage area
+*
+*  This routine frees all the memory allocated to arrays in the common
+*  storage area (CSA). */
+
+static void free_csa(struct csa *csa)
+{     xfree(csa->type);
+      xfree(csa->lb);
+      xfree(csa->ub);
+      xfree(csa->coef);
+      xfree(csa->orig_type);
+      xfree(csa->orig_lb);
+      xfree(csa->orig_ub);
+      xfree(csa->obj);
+      xfree(csa->A_ptr);
+      xfree(csa->A_ind);
+      xfree(csa->A_val);
+#if 1 /* 06/IV-2009 */
+      xfree(csa->AT_ptr);
+      xfree(csa->AT_ind);
+      xfree(csa->AT_val);
+#endif
+      xfree(csa->head);
+#if 1 /* 06/IV-2009 */
+      xfree(csa->bind);
+#endif
+      xfree(csa->stat);
+#if 0 /* 06/IV-2009 */
+      xfree(csa->N_ptr);
+      xfree(csa->N_len);
+      xfree(csa->N_ind);
+      xfree(csa->N_val);
+#endif
+      xfree(csa->bbar);
+      xfree(csa->cbar);
+      xfree(csa->refsp);
+      xfree(csa->gamma);
+      xfree(csa->trow_ind);
+      xfree(csa->trow_vec);
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      xfree(csa->bkpt);
+#endif
+      xfree(csa->tcol_ind);
+      xfree(csa->tcol_vec);
+      xfree(csa->work1);
+      xfree(csa->work2);
+      xfree(csa->work3);
+      xfree(csa->work4);
+      xfree(csa);
+      return;
+}
+
+/***********************************************************************
+*  spx_dual - core LP solver based on the dual simplex method
+*
+*  SYNOPSIS
+*
+*  #include "glpspx.h"
+*  int spx_dual(glp_prob *lp, const glp_smcp *parm);
+*
+*  DESCRIPTION
+*
+*  The routine spx_dual is a core LP solver based on the two-phase dual
+*  simplex method.
+*
+*  RETURNS
+*
+*  0  LP instance has been successfully solved.
+*
+*  GLP_EOBJLL
+*     Objective lower limit has been reached (maximization).
+*
+*  GLP_EOBJUL
+*     Objective upper limit has been reached (minimization).
+*
+*  GLP_EITLIM
+*     Iteration limit has been exhausted.
+*
+*  GLP_ETMLIM
+*     Time limit has been exhausted.
+*
+*  GLP_EFAIL
+*     The solver failed to solve LP instance. */
+
+int spx_dual(glp_prob *lp, const glp_smcp *parm)
+{     struct csa *csa;
+      int binv_st = 2;
+      /* status of basis matrix factorization:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int bbar_st = 0;
+      /* status of primal values of basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int cbar_st = 0;
+      /* status of reduced costs of non-basic variables:
+         0 - invalid; 1 - just computed; 2 - updated */
+      int rigorous = 0;
+      /* rigorous mode flag; this flag is used to enable iterative
+         refinement on computing pivot rows and columns of the simplex
+         table */
+      int check = 0;
+      int p_stat, d_stat, ret;
+      /* allocate and initialize the common storage area */
+      csa = alloc_csa(lp);
+      init_csa(csa, lp);
+      if (parm->msg_lev >= GLP_MSG_DBG)
+         xprintf("Objective scale factor = %g\n", csa->zeta);
+loop: /* main loop starts here */
+      /* compute factorization of the basis matrix */
+      if (binv_st == 0)
+      {  ret = invert_B(csa);
+         if (ret != 0)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+            {  xprintf("Error: unable to factorize the basis matrix (%d"
+                  ")\n", ret);
+               xprintf("Sorry, basis recovery procedure not implemented"
+                  " yet\n");
+            }
+            xassert(!lp->valid && lp->bfd == NULL);
+            lp->bfd = csa->bfd, csa->bfd = NULL;
+            lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+            lp->obj_val = 0.0;
+            lp->it_cnt = csa->it_cnt;
+            lp->some = 0;
+            ret = GLP_EFAIL;
+            goto done;
+         }
+         csa->valid = 1;
+         binv_st = 1; /* just computed */
+         /* invalidate basic solution components */
+         bbar_st = cbar_st = 0;
+      }
+      /* compute reduced costs of non-basic variables */
+      if (cbar_st == 0)
+      {  eval_cbar(csa);
+         cbar_st = 1; /* just computed */
+         /* determine the search phase, if not determined yet */
+         if (csa->phase == 0)
+         {  if (check_feas(csa, 0.90 * parm->tol_dj) != 0)
+            {  /* current basic solution is dual infeasible */
+               /* start searching for dual feasible solution */
+               csa->phase = 1;
+               set_aux_bnds(csa);
+            }
+            else
+            {  /* current basic solution is dual feasible */
+               /* start searching for optimal solution */
+               csa->phase = 2;
+               set_orig_bnds(csa);
+            }
+            xassert(check_stab(csa, parm->tol_dj) == 0);
+            /* some non-basic double-bounded variables might become
+               fixed (on phase I) or vice versa (on phase II) */
+#if 0 /* 06/IV-2009 */
+            build_N(csa);
+#endif
+            csa->refct = 0;
+            /* bounds of non-basic variables have been changed, so
+               invalidate primal values */
+            bbar_st = 0;
+         }
+         /* make sure that the current basic solution remains dual
+            feasible */
+         if (check_stab(csa, parm->tol_dj) != 0)
+         {  if (parm->msg_lev >= GLP_MSG_ERR)
+               xprintf("Warning: numerical instability (dual simplex, p"
+                  "hase %s)\n", csa->phase == 1 ? "I" : "II");
+#if 1
+            if (parm->meth == GLP_DUALP)
+            {  store_sol(csa, lp, GLP_UNDEF, GLP_UNDEF, 0);
+               ret = GLP_EFAIL;
+               goto done;
+            }
+#endif
+            /* restart the search */
+            csa->phase = 0;
+            binv_st = 0;
+            rigorous = 5;
+            goto loop;
+         }
+      }
+      xassert(csa->phase == 1 || csa->phase == 2);
+      /* on phase I we do not need to wait until the current basic
+         solution becomes primal feasible; it is sufficient to make
+         sure that all reduced costs have correct signs */
+      if (csa->phase == 1 && check_feas(csa, parm->tol_dj) == 0)
+      {  /* the current basis is dual feasible; switch to phase II */
+         display(csa, parm, 1);
+         csa->phase = 2;
+         if (cbar_st != 1)
+         {  eval_cbar(csa);
+            cbar_st = 1;
+         }
+         set_orig_bnds(csa);
+#if 0 /* 06/IV-2009 */
+         build_N(csa);
+#endif
+         csa->refct = 0;
+         bbar_st = 0;
+      }
+      /* compute primal values of basic variables */
+      if (bbar_st == 0)
+      {  eval_bbar(csa);
+         if (csa->phase == 2)
+            csa->bbar[0] = eval_obj(csa);
+         bbar_st = 1; /* just computed */
+      }
+      /* redefine the reference space, if required */
+      switch (parm->pricing)
+      {  case GLP_PT_STD:
+            break;
+         case GLP_PT_PSE:
+            if (csa->refct == 0) reset_refsp(csa);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      /* at this point the basis factorization and all basic solution
+         components are valid */
+      xassert(binv_st && bbar_st && cbar_st);
+      /* check accuracy of current basic solution components (only for
+         debugging) */
+      if (check)
+      {  double e_bbar = err_in_bbar(csa);
+         double e_cbar = err_in_cbar(csa);
+         double e_gamma =
+            (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0);
+         xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n",
+            e_bbar, e_cbar, e_gamma);
+         xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3);
+      }
+      /* if the objective has to be maximized, check if it has reached
+         its lower limit */
+      if (csa->phase == 2 && csa->zeta < 0.0 &&
+          parm->obj_ll > -DBL_MAX && csa->bbar[0] <= parm->obj_ll)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("OBJECTIVE LOWER LIMIT REACHED; SEARCH TERMINATED\n"
+               );
+         store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
+         ret = GLP_EOBJLL;
+         goto done;
+      }
+      /* if the objective has to be minimized, check if it has reached
+         its upper limit */
+      if (csa->phase == 2 && csa->zeta > 0.0 &&
+          parm->obj_ul < +DBL_MAX && csa->bbar[0] >= parm->obj_ul)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("OBJECTIVE UPPER LIMIT REACHED; SEARCH TERMINATED\n"
+               );
+         store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0);
+         ret = GLP_EOBJUL;
+         goto done;
+      }
+      /* check if the iteration limit has been exhausted */
+      if (parm->it_lim < INT_MAX &&
+          csa->it_cnt - csa->it_beg >= parm->it_lim)
+      {  if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
+         {  if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               d_stat = GLP_INFEAS;
+               set_orig_bnds(csa);
+               eval_bbar(csa);
+               break;
+            case 2:
+               d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
+         ret = GLP_EITLIM;
+         goto done;
+      }
+      /* check if the time limit has been exhausted */
+      if (parm->tm_lim < INT_MAX &&
+          1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim)
+      {  if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1)
+         {  if (csa->phase == 2 && bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         if (parm->msg_lev >= GLP_MSG_ALL)
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+         switch (csa->phase)
+         {  case 1:
+               d_stat = GLP_INFEAS;
+               set_orig_bnds(csa);
+               eval_bbar(csa);
+               break;
+            case 2:
+               d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, GLP_INFEAS, d_stat, 0);
+         ret = GLP_ETMLIM;
+         goto done;
+      }
+      /* display the search progress */
+      display(csa, parm, 0);
+      /* choose basic variable xB[p] */
+      chuzr(csa, parm->tol_bnd);
+      if (csa->p == 0)
+      {  if (bbar_st != 1 || cbar_st != 1)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n");
+               set_orig_bnds(csa);
+               eval_bbar(csa);
+               p_stat = GLP_INFEAS, d_stat = GLP_NOFEAS;
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("OPTIMAL SOLUTION FOUND\n");
+               p_stat = d_stat = GLP_FEAS;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         store_sol(csa, lp, p_stat, d_stat, 0);
+         ret = 0;
+         goto done;
+      }
+      /* compute pivot row of the simplex table */
+      {  double *rho = csa->work4;
+         eval_rho(csa, rho);
+         if (rigorous) refine_rho(csa, rho);
+         eval_trow(csa, rho);
+         sort_trow(csa, parm->tol_bnd);
+      }
+      /* unlike primal simplex there is no need to check accuracy of
+         the primal value of xB[p] (which might be computed using the
+         pivot row), since bbar is a result of FTRAN */
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      long_step(csa);
+      if (csa->nbps > 0)
+      {  csa->q = csa->bkpt[csa->nbps].j;
+         if (csa->delta > 0.0)
+            csa->new_dq = + csa->bkpt[csa->nbps].t;
+         else
+            csa->new_dq = - csa->bkpt[csa->nbps].t;
+      }
+      else
+#endif
+      /* choose non-basic variable xN[q] */
+      switch (parm->r_test)
+      {  case GLP_RT_STD:
+            chuzc(csa, 0.0);
+            break;
+         case GLP_RT_HAR:
+            chuzc(csa, 0.30 * parm->tol_dj);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      if (csa->q == 0)
+      {  if (bbar_st != 1 || cbar_st != 1 || !rigorous)
+         {  if (bbar_st != 1) bbar_st = 0;
+            if (cbar_st != 1) cbar_st = 0;
+            rigorous = 1;
+            goto loop;
+         }
+         display(csa, parm, 1);
+         switch (csa->phase)
+         {  case 1:
+               if (parm->msg_lev >= GLP_MSG_ERR)
+                  xprintf("Error: unable to choose basic variable on ph"
+                     "ase I\n");
+               xassert(!lp->valid && lp->bfd == NULL);
+               lp->bfd = csa->bfd, csa->bfd = NULL;
+               lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
+               lp->obj_val = 0.0;
+               lp->it_cnt = csa->it_cnt;
+               lp->some = 0;
+               ret = GLP_EFAIL;
+               break;
+            case 2:
+               if (parm->msg_lev >= GLP_MSG_ALL)
+                  xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+               store_sol(csa, lp, GLP_NOFEAS, GLP_FEAS,
+                  csa->head[csa->p]);
+               ret = 0;
+               break;
+            default:
+               xassert(csa != csa);
+         }
+         goto done;
+      }
+      /* check if the pivot element is acceptable */
+      {  double piv = csa->trow_vec[csa->q];
+         double eps = 1e-5 * (1.0 + 0.01 * csa->trow_max);
+         if (fabs(piv) < eps)
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv = %.12g; eps = %g\n", piv, eps);
+            if (!rigorous)
+            {  rigorous = 5;
+               goto loop;
+            }
+         }
+      }
+      /* now xN[q] and xB[p] have been chosen anyhow */
+      /* compute pivot column of the simplex table */
+      eval_tcol(csa);
+      if (rigorous) refine_tcol(csa);
+      /* accuracy check based on the pivot element */
+      {  double piv1 = csa->tcol_vec[csa->p]; /* more accurate */
+         double piv2 = csa->trow_vec[csa->q]; /* less accurate */
+         xassert(piv1 != 0.0);
+         if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) ||
+             !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0))
+         {  if (parm->msg_lev >= GLP_MSG_DBG)
+               xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2);
+            if (binv_st != 1 || !rigorous)
+            {  if (binv_st != 1) binv_st = 0;
+               rigorous = 5;
+               goto loop;
+            }
+            /* (not a good idea; should be revised later) */
+            if (csa->tcol_vec[csa->p] == 0.0)
+            {  csa->tcol_nnz++;
+               xassert(csa->tcol_nnz <= csa->m);
+               csa->tcol_ind[csa->tcol_nnz] = csa->p;
+            }
+            csa->tcol_vec[csa->p] = piv2;
+         }
+      }
+      /* update primal values of basic variables */
+#ifdef GLP_LONG_STEP /* 07/IV-2009 */
+      if (csa->nbps > 0)
+      {  int kk, j, k;
+         for (kk = 1; kk < csa->nbps; kk++)
+         {  if (csa->bkpt[kk].t >= csa->bkpt[csa->nbps].t) continue;
+            j = csa->bkpt[kk].j;
+            k = csa->head[csa->m + j];
+            xassert(csa->type[k] == GLP_DB);
+            if (csa->stat[j] == GLP_NL)
+               csa->stat[j] = GLP_NU;
+            else
+               csa->stat[j] = GLP_NL;
+         }
+      }
+      bbar_st = 0;
+#else
+      update_bbar(csa);
+      if (csa->phase == 2)
+         csa->bbar[0] += (csa->cbar[csa->q] / csa->zeta) *
+            (csa->delta / csa->tcol_vec[csa->p]);
+      bbar_st = 2; /* updated */
+#endif
+      /* update reduced costs of non-basic variables */
+      update_cbar(csa);
+      cbar_st = 2; /* updated */
+      /* update steepest edge coefficients */
+      switch (parm->pricing)
+      {  case GLP_PT_STD:
+            break;
+         case GLP_PT_PSE:
+            if (csa->refct > 0) update_gamma(csa);
+            break;
+         default:
+            xassert(parm != parm);
+      }
+      /* update factorization of the basis matrix */
+      ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]);
+      if (ret == 0)
+         binv_st = 2; /* updated */
+      else
+      {  csa->valid = 0;
+         binv_st = 0; /* invalid */
+      }
+#if 0 /* 06/IV-2009 */
+      /* update matrix N */
+      del_N_col(csa, csa->q, csa->head[csa->m+csa->q]);
+      if (csa->type[csa->head[csa->p]] != GLP_FX)
+         add_N_col(csa, csa->q, csa->head[csa->p]);
+#endif
+      /* change the basis header */
+      change_basis(csa);
+      /* iteration complete */
+      csa->it_cnt++;
+      if (rigorous > 0) rigorous--;
+      goto loop;
+done: /* deallocate the common storage area */
+      free_csa(csa);
+      /* return to the calling program */
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpsql.c
===================================================================
--- deps/glpk/src/glpsql.c	(revision 9)
+++ deps/glpk/src/glpsql.c	(revision 9)
@@ -0,0 +1,1631 @@
+/* glpsql.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Author: Heinrich Schuchardt <xypron.glpk@gmx.de>.
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glpmpl.h"
+#include "glpsql.h"
+
+#ifdef ODBC_DLNAME
+#define HAVE_ODBC
+#define libodbc ODBC_DLNAME
+#define h_odbc (get_env_ptr()->h_odbc)
+#endif
+
+#ifdef MYSQL_DLNAME
+#define HAVE_MYSQL
+#define libmysql MYSQL_DLNAME
+#define h_mysql (get_env_ptr()->h_mysql)
+#endif
+
+static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
+      **sqllines);
+static void *db_mysql_open_int(TABDCA *dca, int mode, const char
+      **sqllines);
+
+/**********************************************************************/
+
+#if defined(HAVE_ODBC) || defined(HAVE_MYSQL)
+
+#define SQL_FIELD_MAX 100
+/* maximal field count */
+
+#define SQL_FDLEN_MAX 255
+/* maximal field length */
+
+/***********************************************************************
+*  NAME
+*
+*  args_concat - concatenate arguments
+*
+*  SYNOPSIS
+*
+*  static char **args_concat(TABDCA *dca);
+*
+*  DESCRIPTION
+*
+*  The arguments passed in dca are SQL statements. A SQL statement may
+*  be split over multiple arguments. The last argument of a SQL
+*  statement will be terminated with a semilocon. Each SQL statement is
+*  merged into a single zero terminated string. Boundaries between
+*  arguments are replaced by space.
+*
+*  RETURNS
+*
+*  Buffer with SQL statements */
+
+static char **args_concat(TABDCA *dca)
+{
+   const char  *arg;
+   int          i;
+   int          j;
+   int          j0;
+   int          j1;
+   int          len;
+   int          lentot;
+   int          narg;
+   int          nline = 0;
+   void        *ret;
+   char       **sqllines = NULL;
+
+   narg = mpl_tab_num_args(dca);
+   /* The SQL statements start with argument 3. */
+   if (narg < 3)
+      return NULL;
+   /* Count the SQL statements */
+   for (j = 3; j <= narg; j++)
+   {
+      arg = mpl_tab_get_arg(dca, j);
+      len = strlen(arg);
+      if (arg[len-1] == ';' || j == narg)
+        nline ++;
+   }
+   /* Allocate string buffer. */
+   sqllines = (char **) xmalloc((nline+1) * sizeof(char **));
+   /* Join arguments */
+   sqllines[0] = NULL;
+   j0     = 3;
+   i      = 0;
+   lentot = 0;
+   for (j = 3; j <= narg; j++)
+   {
+      arg = mpl_tab_get_arg(dca, j);
+      len = strlen(arg);
+      /* add length of part */
+      lentot += len;
+      /* add length of space separating parts or 0x00 at end of SQL
+         statement */
+      lentot++;
+      if (arg[len-1] == ';' || j == narg)
+      {  /* Join arguments for a single SQL statement */
+         sqllines[i] = xmalloc(lentot);
+         sqllines[i+1] = NULL;
+         sqllines[i][0] = 0x00;
+         for (j1 = j0; j1 <= j; j1++)
+         {  if(j1>j0)
+               strcat(sqllines[i], " ");
+            strcat(sqllines[i], mpl_tab_get_arg(dca, j1));
+         }
+         len = strlen(sqllines[i]);
+         if (sqllines[i][len-1] == ';')
+            sqllines[i][len-1] = 0x00;
+         j0 = j+1;
+         i++;
+         lentot = 0;
+      }
+   }
+   return sqllines;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  free_buffer - free multiline string buffer
+*
+*  SYNOPSIS
+*
+*  static void free_buffer(char **buf);
+*
+*  DESCRIPTION
+*
+*  buf is a list of strings terminated by NULL.
+*  The memory for the strings and for the list is released. */
+
+static void free_buffer(char **buf)
+{  int i;
+
+   for(i = 0; buf[i] != NULL; i++)
+      xfree(buf[i]);
+   xfree(buf);
+}
+
+static int db_escaped_string_length(const char* from)
+/* length of escaped string */
+{
+   int         count;
+   const char *pointer;
+
+    for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++,
+         count++)
+    {
+      switch (*pointer)
+      {
+         case '\'':
+            count++;
+            break;
+      }
+    }
+
+    return count;
+}
+
+static int db_escape_string (char *to, const char *from)
+/* escape string*/
+{
+   const char *source = from;
+   char *target = to;
+   unsigned int remaining;
+
+   remaining = strlen(from);
+
+   if (to == NULL)
+     to = (char *) (from + remaining);
+
+   while (remaining > 0)
+   {
+      switch (*source)
+      {
+         case '\'':
+            *target = '\'';
+            target++;
+            *target = '\'';
+            break;
+
+         default:
+            *target = *source;
+            }
+      source++;
+      target++;
+      remaining--;
+      }
+
+   /* Write the terminating NUL character. */
+   *target = '\0';
+
+   return target - to;
+}
+
+static char *db_generate_select_stmt(TABDCA *dca)
+/* generate select statement */
+{
+   char        *arg;
+   char const  *field;
+   char        *query;
+   int          j;
+   int          narg;
+   int          nf;
+   int          total;
+
+   total = 50;
+   nf = mpl_tab_num_flds(dca);
+   narg = mpl_tab_num_args(dca);
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      total += strlen(field);
+      total += 2;
+   }
+   arg = (char *) mpl_tab_get_arg(dca, narg);
+   total += strlen(arg);
+   query = xmalloc( total * sizeof(char));
+   strcpy (query, "SELECT ");
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      strcat(query, field);
+      if ( j < nf )
+         strcat(query, ", ");
+   }
+   strcat(query, " FROM ");
+   strcat(query, arg);
+   return query;
+}
+
+static char *db_generate_insert_stmt(TABDCA *dca)
+/* generate insert statement */
+{
+   char        *arg;
+   char const  *field;
+   char        *query;
+   int          j;
+   int          narg;
+   int          nf;
+   int          total;
+
+   total = 50;
+   nf = mpl_tab_num_flds(dca);
+   narg = mpl_tab_num_args(dca);
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      total += strlen(field);
+      total += 5;
+   }
+   arg = (char *) mpl_tab_get_arg(dca, narg);
+   total += strlen(arg);
+   query = xmalloc( (total+1) * sizeof(char));
+   strcpy (query, "INSERT INTO ");
+   strcat(query, arg);
+   strcat(query, " ( ");
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      field = mpl_tab_get_name(dca, j);
+      strcat(query, field);
+      if ( j < nf )
+         strcat(query, ", ");
+   }
+   strcat(query, " ) VALUES ( ");
+   for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++)
+   {
+      strcat(query, "?");
+      if ( j < nf )
+         strcat(query, ", ");
+   }
+   strcat(query, " )");
+   return query;
+}
+
+#endif
+
+/**********************************************************************/
+
+#ifndef HAVE_ODBC
+
+void *db_iodbc_open(TABDCA *dca, int mode)
+{     xassert(dca == dca);
+      xassert(mode == mode);
+      xprintf("iODBC table driver not supported\n");
+      return NULL;
+}
+
+int db_iodbc_read(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_iodbc_write(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_iodbc_close(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+#else
+
+#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
+#include <windows.h>
+#endif
+
+#include <sql.h>
+#include <sqlext.h>
+
+struct db_odbc
+{
+   int              mode;         /*'R' = Read, 'W' = Write*/
+   SQLHDBC          hdbc;         /*connection handle*/
+   SQLHENV          henv;         /*environment handle*/
+   SQLHSTMT         hstmt;        /*statement handle*/
+   SQLSMALLINT      nresultcols;  /* columns in result*/
+   SQLULEN          collen[SQL_FIELD_MAX+1];
+   SQLLEN           outlen[SQL_FIELD_MAX+1];
+   SQLSMALLINT      coltype[SQL_FIELD_MAX+1];
+   SQLCHAR          data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
+   SQLCHAR          colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1];
+   int              isnumeric[SQL_FIELD_MAX+1];
+   int              nf;
+   /* number of fields in the csv file */
+   int              ref[1+SQL_FIELD_MAX];
+   /* ref[k] = k', if k-th field of the csv file corresponds to
+      k'-th field in the table statement; if ref[k] = 0, k-th field
+      of the csv file is ignored */
+   SQLCHAR         *query;
+   /* query generated by db_iodbc_open */
+};
+
+SQLRETURN SQL_API dl_SQLAllocHandle (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             InputHandle,
+   SQLHANDLE            *OutputHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLAllocHandle(
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             InputHandle,
+         SQLHANDLE            *OutputHandle);
+
+      ep_SQLAllocHandle *fn;
+      fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, InputHandle, OutputHandle);
+}
+
+SQLRETURN SQL_API dl_SQLBindCol (
+   SQLHSTMT              StatementHandle,
+   SQLUSMALLINT          ColumnNumber,
+   SQLSMALLINT           TargetType,
+   SQLPOINTER            TargetValue,
+   SQLLEN                BufferLength,
+   SQLLEN               *StrLen_or_Ind)
+{
+      typedef SQLRETURN SQL_API ep_SQLBindCol(
+         SQLHSTMT              StatementHandle,
+         SQLUSMALLINT          ColumnNumber,
+         SQLSMALLINT           TargetType,
+         SQLPOINTER            TargetValue,
+         SQLLEN                BufferLength,
+         SQLLEN               *StrLen_or_Ind);
+      ep_SQLBindCol *fn;
+      fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, ColumnNumber, TargetType,
+         TargetValue, BufferLength, StrLen_or_Ind);
+}
+
+SQLRETURN SQL_API dl_SQLCloseCursor (
+   SQLHSTMT              StatementHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLCloseCursor (
+         SQLHSTMT              StatementHandle);
+
+      ep_SQLCloseCursor *fn;
+      fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle);
+}
+
+
+SQLRETURN SQL_API dl_SQLDisconnect (
+   SQLHDBC               ConnectionHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLDisconnect(
+         SQLHDBC               ConnectionHandle);
+
+      ep_SQLDisconnect *fn;
+      fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect");
+      xassert(fn != NULL);
+      return (*fn)(ConnectionHandle);
+}
+
+SQLRETURN SQL_API dl_SQLDriverConnect (
+   SQLHDBC               hdbc,
+   SQLHWND               hwnd,
+   SQLCHAR              *szConnStrIn,
+   SQLSMALLINT           cbConnStrIn,
+   SQLCHAR              *szConnStrOut,
+   SQLSMALLINT           cbConnStrOutMax,
+   SQLSMALLINT          *pcbConnStrOut,
+   SQLUSMALLINT          fDriverCompletion)
+{
+      typedef SQLRETURN SQL_API ep_SQLDriverConnect(
+         SQLHDBC               hdbc,
+         SQLHWND               hwnd,
+         SQLCHAR             * szConnStrIn,
+         SQLSMALLINT           cbConnStrIn,
+         SQLCHAR             * szConnStrOut,
+         SQLSMALLINT           cbConnStrOutMax,
+         SQLSMALLINT         * pcbConnStrOut,
+         SQLUSMALLINT          fDriverCompletion);
+
+      ep_SQLDriverConnect *fn;
+      fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect");
+      xassert(fn != NULL);
+      return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut,
+         cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
+}
+
+SQLRETURN SQL_API dl_SQLEndTran (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             Handle,
+   SQLSMALLINT           CompletionType)
+{
+      typedef SQLRETURN SQL_API ep_SQLEndTran (
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             Handle,
+         SQLSMALLINT           CompletionType);
+
+      ep_SQLEndTran *fn;
+      fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, Handle, CompletionType);
+}
+
+SQLRETURN SQL_API dl_SQLExecDirect (
+   SQLHSTMT              StatementHandle,
+   SQLCHAR             * StatementText,
+   SQLINTEGER            TextLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLExecDirect (
+         SQLHSTMT              StatementHandle,
+         SQLCHAR             * StatementText,
+         SQLINTEGER            TextLength);
+
+      ep_SQLExecDirect *fn;
+      fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, StatementText, TextLength);
+}
+
+SQLRETURN SQL_API dl_SQLFetch (
+   SQLHSTMT              StatementHandle)
+{
+      typedef SQLRETURN SQL_API ep_SQLFetch (
+         SQLHSTMT              StatementHandle);
+
+      ep_SQLFetch *fn;
+      fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle);
+}
+
+SQLRETURN SQL_API dl_SQLFreeHandle (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             Handle)
+{
+      typedef SQLRETURN SQL_API ep_SQLFreeHandle (
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             Handle);
+
+      ep_SQLFreeHandle *fn;
+      fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, Handle);
+}
+
+SQLRETURN SQL_API dl_SQLDescribeCol (
+   SQLHSTMT              StatementHandle,
+   SQLUSMALLINT          ColumnNumber,
+   SQLCHAR             * ColumnName,
+   SQLSMALLINT           BufferLength,
+   SQLSMALLINT         * NameLength,
+   SQLSMALLINT         * DataType,
+   SQLULEN             * ColumnSize,
+   SQLSMALLINT         * DecimalDigits,
+   SQLSMALLINT         * Nullable)
+{
+      typedef SQLRETURN SQL_API ep_SQLDescribeCol (
+         SQLHSTMT              StatementHandle,
+         SQLUSMALLINT          ColumnNumber,
+         SQLCHAR              *ColumnName,
+         SQLSMALLINT           BufferLength,
+         SQLSMALLINT          *NameLength,
+         SQLSMALLINT          *DataType,
+         SQLULEN              *ColumnSize,
+         SQLSMALLINT          *DecimalDigits,
+         SQLSMALLINT          *Nullable);
+
+      ep_SQLDescribeCol *fn;
+      fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, ColumnNumber, ColumnName,
+         BufferLength, NameLength,
+         DataType, ColumnSize, DecimalDigits, Nullable);
+}
+
+SQLRETURN SQL_API dl_SQLGetDiagRec (
+   SQLSMALLINT           HandleType,
+   SQLHANDLE             Handle,
+   SQLSMALLINT           RecNumber,
+   SQLCHAR              *Sqlstate,
+   SQLINTEGER           *NativeError,
+   SQLCHAR              *MessageText,
+   SQLSMALLINT           BufferLength,
+   SQLSMALLINT          *TextLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLGetDiagRec (
+         SQLSMALLINT           HandleType,
+         SQLHANDLE             Handle,
+         SQLSMALLINT           RecNumber,
+         SQLCHAR              *Sqlstate,
+         SQLINTEGER           *NativeError,
+         SQLCHAR              *MessageText,
+         SQLSMALLINT           BufferLength,
+         SQLSMALLINT          *TextLength);
+
+      ep_SQLGetDiagRec *fn;
+      fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec");
+      xassert(fn != NULL);
+      return (*fn)(HandleType, Handle, RecNumber, Sqlstate,
+         NativeError, MessageText, BufferLength, TextLength);
+}
+
+SQLRETURN SQL_API dl_SQLGetInfo (
+   SQLHDBC               ConnectionHandle,
+   SQLUSMALLINT          InfoType,
+   SQLPOINTER            InfoValue,
+   SQLSMALLINT           BufferLength,
+   SQLSMALLINT          *StringLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLGetInfo (
+         SQLHDBC               ConnectionHandle,
+         SQLUSMALLINT          InfoType,
+         SQLPOINTER            InfoValue,
+         SQLSMALLINT           BufferLength,
+         SQLSMALLINT          *StringLength);
+
+      ep_SQLGetInfo *fn;
+      fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo");
+      xassert(fn != NULL);
+      return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength,
+         StringLength);
+}
+
+SQLRETURN SQL_API dl_SQLNumResultCols (
+   SQLHSTMT              StatementHandle,
+   SQLSMALLINT          *ColumnCount)
+{
+      typedef SQLRETURN SQL_API ep_SQLNumResultCols (
+         SQLHSTMT              StatementHandle,
+         SQLSMALLINT          *ColumnCount);
+
+      ep_SQLNumResultCols *fn;
+      fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols");
+      xassert(fn != NULL);
+      return (*fn)(StatementHandle, ColumnCount);
+}
+
+SQLRETURN SQL_API dl_SQLSetConnectAttr (
+   SQLHDBC               ConnectionHandle,
+   SQLINTEGER            Attribute,
+   SQLPOINTER            Value,
+   SQLINTEGER            StringLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLSetConnectAttr (
+         SQLHDBC               ConnectionHandle,
+         SQLINTEGER            Attribute,
+         SQLPOINTER            Value,
+         SQLINTEGER            StringLength);
+
+      ep_SQLSetConnectAttr *fn;
+     fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr");
+      xassert(fn != NULL);
+      return (*fn)(ConnectionHandle, Attribute, Value, StringLength);
+}
+
+SQLRETURN SQL_API dl_SQLSetEnvAttr (
+   SQLHENV               EnvironmentHandle,
+   SQLINTEGER            Attribute,
+   SQLPOINTER            Value,
+   SQLINTEGER            StringLength)
+{
+      typedef SQLRETURN SQL_API ep_SQLSetEnvAttr (
+         SQLHENV               EnvironmentHandle,
+         SQLINTEGER            Attribute,
+         SQLPOINTER            Value,
+         SQLINTEGER            StringLength);
+
+      ep_SQLSetEnvAttr *fn;
+      fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr");
+      xassert(fn != NULL);
+      return (*fn)(EnvironmentHandle, Attribute, Value, StringLength);
+}
+
+static void extract_error(
+   char *fn,
+   SQLHANDLE handle,
+   SQLSMALLINT type);
+
+static int is_numeric(
+    SQLSMALLINT coltype);
+
+/***********************************************************************
+*  NAME
+*
+*  db_iodbc_open - open connection to ODBC data base
+*
+*  SYNOPSIS
+*
+*  #include "glpsql.h"
+*  void *db_iodbc_open(TABDCA *dca, int mode);
+*
+*  DESCRIPTION
+*
+*  The routine db_iodbc_open opens a connection to an ODBC data base.
+*  It then executes the sql statements passed.
+*
+*  In the case of table read the SELECT statement is executed.
+*
+*  In the case of table write the INSERT statement is prepared.
+*  RETURNS
+*
+*  The routine returns a pointer to data storage area created. */
+void *db_iodbc_open(TABDCA *dca, int mode)
+{  void  *ret;
+   char **sqllines;
+
+   sqllines = args_concat(dca);
+   if (sqllines == NULL)
+   {  xprintf("Missing arguments in table statement.\n"
+              "Please, supply table driver, dsn, and query.\n");
+      return NULL;
+   }
+   ret = db_iodbc_open_int(dca, mode, (const char **) sqllines);
+   free_buffer(sqllines);
+   return ret;
+}
+
+static void *db_iodbc_open_int(TABDCA *dca, int mode, const char
+   **sqllines)
+{
+   struct db_odbc    *sql;
+   SQLRETURN          ret;
+   SQLCHAR FAR       *dsn;
+   SQLCHAR            info[256];
+   SQLSMALLINT        colnamelen;
+   SQLSMALLINT        nullable;
+   SQLSMALLINT        scale;
+   const char        *arg;
+   int                narg;
+   int                i, j;
+   int                total;
+
+   if (libodbc == NULL)
+   {
+      xprintf("No loader for shared ODBC library available\n");
+      return NULL;
+   }
+
+   if (h_odbc == NULL)
+   {
+      h_odbc = xdlopen(libodbc);
+      if (h_odbc == NULL)
+      {  xprintf("unable to open library %s\n", libodbc);
+         xprintf("%s\n", xerrmsg());
+         return NULL;
+      }
+   }
+
+   sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc));
+   if (sql == NULL)
+         return NULL;
+
+   sql->mode  = mode;
+   sql->hdbc  = NULL;
+   sql->henv  = NULL;
+   sql->hstmt = NULL;
+   sql->query = NULL;
+   narg = mpl_tab_num_args(dca);
+
+   dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2);
+   /* allocate an environment handle */
+   ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
+      &(sql->henv));
+   /* set attribute to enable application to run as ODBC 3.0
+      application */
+   ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION,
+      (void *) SQL_OV_ODBC3, 0);
+   /* allocate a connection handle */
+   ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc));
+   /* connect */
+   ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0,
+      NULL, SQL_DRIVER_COMPLETE);
+   if (SQL_SUCCEEDED(ret))
+   {  /* output information about data base connection */
+      xprintf("Connected to ");
+      dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info,
+         sizeof(info), NULL);
+      xprintf("%s ", info);
+      dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info,
+         sizeof(info), NULL);
+      xprintf("%s - ", info);
+      dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info,
+         sizeof(info), NULL);
+      xprintf("%s\n", info);
+   }
+   else
+   {  /* describe error */
+      xprintf("Failed to connect\n");
+      extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC);
+      dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+      dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+      xfree(sql);
+      return NULL;
+   }
+   /* set AUTOCOMMIT on*/
+   ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT,
+      (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
+   /* allocate a statement handle */
+   ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt));
+
+   /* initialization queries */
+   for(j = 0; sqllines[j+1] != NULL; j++)
+   {
+      sql->query = (SQLCHAR *) sqllines[j];
+      xprintf("%s\n", sql->query);
+      ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS);
+      switch (ret)
+      {
+         case SQL_SUCCESS:
+         case SQL_SUCCESS_WITH_INFO:
+         case SQL_NO_DATA_FOUND:
+            break;
+         default:
+            xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n",
+               sql->query);
+            extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
+            dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+            dl_SQLDisconnect(sql->hdbc);
+            dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+            dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+            xfree(sql);
+            return NULL;
+      }
+      /* commit statement */
+      dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
+   }
+
+   if ( sql->mode == 'R' )
+   {  sql->nf = mpl_tab_num_flds(dca);
+      for(j = 0; sqllines[j] != NULL; j++)
+         arg = sqllines[j];
+      total = strlen(arg);
+      if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
+      {
+         total = strlen(arg);
+         sql->query = xmalloc( (total+1) * sizeof(char));
+         strcpy (sql->query, arg);
+      }
+      else
+      {
+         sql->query = db_generate_select_stmt(dca);
+      }
+      xprintf("%s\n", sql->query);
+      if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) !=
+         SQL_SUCCESS)
+      {
+         xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query);
+         extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT);
+         dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+         dl_SQLDisconnect(sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+         xfree(sql->query);
+            xfree(sql);
+         return NULL;
+      }
+      xfree(sql->query);
+      /* determine number of result columns */
+      ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols);
+      total = sql->nresultcols;
+      if (total > SQL_FIELD_MAX)
+      {  xprintf("db_iodbc_open: Too many fields (> %d) in query.\n"
+            "\"%s\"\n", SQL_FIELD_MAX, sql->query);
+         dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+         dl_SQLDisconnect(sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+         dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+         xfree(sql->query);
+         return NULL;
+      }
+      for (i = 1; i <= total; i++)
+      {  /* return a set of attributes for a column */
+         ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i,
+            sql->colname[i], SQL_FDLEN_MAX,
+            &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale,
+            &nullable);
+         sql->isnumeric[i] = is_numeric(sql->coltype[i]);
+         /* bind columns to program vars, converting all types to CHAR*/
+         if (sql->isnumeric[i])
+         {  dl_SQLBindCol(sql->hstmt, i, SQL_DOUBLE, sql->data[i],
+               SQL_FDLEN_MAX, &(sql->outlen[i]));
+         } else
+         {  dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i],
+               SQL_FDLEN_MAX, &(sql->outlen[i]));
+         }
+         for (j = sql->nf; j >= 1; j--)
+         {  if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0)
+            break;
+         }
+         sql->ref[i] = j;
+      }
+   }
+   else if ( sql->mode == 'W' )
+   {  for(j = 0; sqllines[j] != NULL; j++)
+         arg = sqllines[j];
+      if (  NULL != strchr(arg, '?') )
+      {
+         total = strlen(arg);
+         sql->query = xmalloc( (total+1) * sizeof(char));
+         strcpy (sql->query, arg);
+         }
+      else
+      {
+         sql->query = db_generate_insert_stmt(dca);
+      }
+      xprintf("%s\n", sql->query);
+   }
+   return sql;
+}
+
+int db_iodbc_read(TABDCA *dca, void *link)
+{
+   struct db_odbc  *sql;
+   SQLRETURN        ret;
+   char             buf[SQL_FDLEN_MAX+1];
+   int              i;
+   int              len;
+   double           num;
+
+   sql = (struct db_odbc *) link;
+
+   xassert(sql != NULL);
+   xassert(sql->mode == 'R');
+
+   ret=dl_SQLFetch(sql->hstmt);
+   if (ret== SQL_ERROR)
+      return -1;
+   if (ret== SQL_NO_DATA_FOUND)
+      return -1; /*EOF*/
+   for (i=1; i <= sql->nresultcols; i++)
+   {
+      if (sql->ref[i] > 0)
+      {
+         len = sql->outlen[i];
+         if (len != SQL_NULL_DATA)
+         {
+            if (sql->isnumeric[i])
+            {  mpl_tab_set_num(dca, sql->ref[i],
+                               *((const double *) sql->data[i]));
+            }
+            else
+            {  if (len > SQL_FDLEN_MAX)
+                  len = SQL_FDLEN_MAX;
+               else if (len < 0)
+                  len = 0;
+               strncpy(buf, (const char *) sql->data[i], len);
+               buf[len] = 0x00;
+               mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
+            }
+         }
+      }
+   }
+   return 0;
+}
+
+int db_iodbc_write(TABDCA *dca, void *link)
+{
+   struct db_odbc  *sql;
+   char            *part;
+   char            *query;
+   char            *template;
+   char             num[50];
+   int              k;
+   int              len;
+   int              nf;
+
+   sql = (struct db_odbc *) link;
+   xassert(sql != NULL);
+   xassert(sql->mode == 'W');
+
+   len      = strlen(sql->query);
+   template = (char *) xmalloc( (len + 1) * sizeof(char) );
+   strcpy(template, sql->query);
+
+   nf = mpl_tab_num_flds(dca);
+   for (k = 1; k <= nf; k++)
+   {     switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+            len += 20;
+            break;
+         case 'S':
+            len += db_escaped_string_length(mpl_tab_get_str(dca, k));
+            len += 2;
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   query = xmalloc( (len + 1 ) * sizeof(char) );
+   query[0] = 0x00;
+   for (k = 1, part = strtok (template, "?"); (part != NULL);
+      part = strtok (NULL, "?"), k++)
+   {
+      if (k > nf) break;
+      strcat( query, part );
+      switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+#if 0 /* 02/XI-2010 by xypron */
+            sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
+#else
+            sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+#endif
+            strcat( query, num );
+            break;
+         case 'S':
+            strcat( query, "'");
+            db_escape_string( query + strlen(query),
+               mpl_tab_get_str(dca, k) );
+            strcat( query, "'");
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   if (part != NULL)
+      strcat(query, part);
+   if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS)
+      != SQL_SUCCESS)
+   {
+      xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query);
+      extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC);
+      xfree(query);
+      xfree(template);
+      return 1;
+      }
+
+   xfree(query);
+   xfree(template);
+   return 0;
+}
+
+int db_iodbc_close(TABDCA *dca, void *link)
+{
+   struct db_odbc *sql;
+
+   sql = (struct db_odbc *) link;
+   xassert(sql != NULL);
+   /* Commit */
+   if ( sql->mode == 'W' )
+      dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT);
+   if ( sql->mode == 'R' )
+      dl_SQLCloseCursor(sql->hstmt);
+
+   dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt);
+   dl_SQLDisconnect(sql->hdbc);
+   dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc);
+   dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv);
+   if ( sql->mode == 'W' )
+      xfree(sql->query);
+   xfree(sql);
+   dca->link = NULL;
+   return 0;
+}
+
+static void extract_error(
+   char *fn,
+   SQLHANDLE handle,
+   SQLSMALLINT type)
+{
+   SQLINTEGER   i = 0;
+   SQLINTEGER   native;
+   SQLCHAR   state[ 7 ];
+   SQLCHAR   text[256];
+   SQLSMALLINT  len;
+   SQLRETURN    ret;
+
+   xprintf("\nThe driver reported the following diagnostics whilst "
+      "running %s\n", fn);
+
+   do
+   {
+      ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text,
+         sizeof(text), &len );
+      if (SQL_SUCCEEDED(ret))
+         xprintf("%s:%ld:%ld:%s\n", state, i, native, text);
+   }
+   while( ret == SQL_SUCCESS );
+}
+
+static int is_numeric(SQLSMALLINT coltype)
+{
+   int ret = 0;
+   switch (coltype)
+   {
+      case SQL_DECIMAL:
+      case SQL_NUMERIC:
+      case SQL_SMALLINT:
+      case SQL_INTEGER:
+      case SQL_REAL:
+      case SQL_FLOAT:
+      case SQL_DOUBLE:
+      case SQL_TINYINT:
+      case SQL_BIGINT:
+         ret = 1;
+         break;
+   }
+   return ret;
+}
+
+#endif
+
+/**********************************************************************/
+
+#ifndef HAVE_MYSQL
+
+void *db_mysql_open(TABDCA *dca, int mode)
+{     xassert(dca == dca);
+      xassert(mode == mode);
+      xprintf("MySQL table driver not supported\n");
+      return NULL;
+}
+
+int db_mysql_read(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_mysql_write(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+int db_mysql_close(TABDCA *dca, void *link)
+{     xassert(dca != dca);
+      xassert(link != link);
+      return 0;
+}
+
+#else
+
+#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__)
+#include <windows.h>
+#endif
+
+#ifdef __CYGWIN__
+#define byte_defined 1
+#endif
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <mysql.h>
+
+struct db_mysql
+{
+   int              mode;  /*'R' = Read, 'W' = Write*/
+   MYSQL           *con;   /*connection*/
+   MYSQL_RES       *res;    /*result*/
+   int              nf;
+   /* number of fields in the csv file */
+   int              ref[1+SQL_FIELD_MAX];
+   /* ref[k] = k', if k-th field of the csv file corresponds to
+      k'-th field in the table statement; if ref[k] = 0, k-th field
+      of the csv file is ignored */
+   char            *query;
+   /* query generated by db_mysql_open */
+};
+
+void STDCALL dl_mysql_close(MYSQL *sock)
+{
+      typedef void STDCALL ep_mysql_close(MYSQL *sock);
+
+      ep_mysql_close *fn;
+      fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close");
+      xassert(fn != NULL);
+      return (*fn)(sock);
+}
+
+const char * STDCALL dl_mysql_error(MYSQL *mysql)
+{
+      typedef const char * STDCALL ep_mysql_error(MYSQL *mysql);
+
+      ep_mysql_error *fn;
+      fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res)
+{
+      typedef MYSQL_FIELD * STDCALL
+         ep_mysql_fetch_fields(MYSQL_RES *res);
+
+      ep_mysql_fetch_fields *fn;
+   fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields");
+      xassert(fn != NULL);
+      return (*fn)(res);
+}
+
+unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result)
+{
+      typedef unsigned long * STDCALL
+         ep_mysql_fetch_lengths(MYSQL_RES *result);
+
+      ep_mysql_fetch_lengths *fn;
+      fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql,
+         "mysql_fetch_lengths");
+      xassert(fn != NULL);
+      return (*fn)(result);
+}
+
+MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result)
+{
+      typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result);
+
+      ep_mysql_fetch_row *fn;
+      fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row");
+      xassert(fn != NULL);
+      return (*fn)(result);
+}
+
+unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql)
+{
+      typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql);
+
+      ep_mysql_field_count *fn;
+     fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+MYSQL * STDCALL dl_mysql_init(MYSQL *mysql)
+{
+      typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql);
+
+      ep_mysql_init *fn;
+      fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res)
+{
+      typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res);
+
+      ep_mysql_num_fields *fn;
+      fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields");
+      xassert(fn != NULL);
+      return (*fn)(res);
+}
+
+int STDCALL dl_mysql_query(MYSQL *mysql, const char *q)
+{
+      typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q);
+
+      ep_mysql_query *fn;
+      fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query");
+      xassert(fn != NULL);
+      return (*fn)(mysql, q);
+}
+
+MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host,
+                                           const char *user,
+                                           const char *passwd,
+                                           const char *db,
+                                           unsigned int port,
+                                           const char *unix_socket,
+                                           unsigned long clientflag)
+{
+      typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql,
+            const char *host,
+            const char *user,
+            const char *passwd,
+            const char *db,
+            unsigned int port,
+            const char *unix_socket,
+            unsigned long clientflag);
+
+      ep_mysql_real_connect *fn;
+      fn = (ep_mysql_real_connect *) xdlsym(h_mysql,
+         "mysql_real_connect");
+      xassert(fn != NULL);
+      return (*fn)(mysql, host, user, passwd, db, port, unix_socket,
+         clientflag);
+}
+
+MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql)
+{
+      typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql);
+      ep_mysql_use_result *fn;
+      fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result");
+      xassert(fn != NULL);
+      return (*fn)(mysql);
+}
+
+/***********************************************************************
+*  NAME
+*
+*  db_mysql_open - open connection to ODBC data base
+*
+*  SYNOPSIS
+*
+*  #include "glpsql.h"
+*  void *db_mysql_open(TABDCA *dca, int mode);
+*
+*  DESCRIPTION
+*
+*  The routine db_mysql_open opens a connection to a MySQL data base.
+*  It then executes the sql statements passed.
+*
+*  In the case of table read the SELECT statement is executed.
+*
+*  In the case of table write the INSERT statement is prepared.
+*  RETURNS
+*
+*  The routine returns a pointer to data storage area created. */
+
+void *db_mysql_open(TABDCA *dca, int mode)
+{  void  *ret;
+   char **sqllines;
+
+   sqllines = args_concat(dca);
+   if (sqllines == NULL)
+   {  xprintf("Missing arguments in table statement.\n"
+              "Please, supply table driver, dsn, and query.\n");
+      return NULL;
+   }
+   ret = db_mysql_open_int(dca, mode, (const char **) sqllines);
+   free_buffer(sqllines);
+   return ret;
+}
+
+static void *db_mysql_open_int(TABDCA *dca, int mode, const char
+   **sqllines)
+{
+   struct db_mysql *sql = NULL;
+   char            *arg = NULL;
+   const char      *field;
+   MYSQL_FIELD     *fields;
+   char            *keyword;
+   char            *value;
+   char            *query;
+   char            *dsn;
+/* "Server=[server_name];Database=[database_name];UID=[username];*/
+/* PWD=[password];Port=[port]"*/
+   char            *server   = NULL;        /* Server */
+   char            *user     = NULL;        /* UID */
+   char            *password = NULL;        /* PWD */
+   char            *database = NULL;        /* Database */
+   unsigned int     port = 0;               /* Port */
+   int              narg;
+   int              i, j, total;
+
+   if (libmysql == NULL)
+   {
+      xprintf("No loader for shared MySQL library available\n");
+      return NULL;
+   }
+
+   if (h_mysql == NULL)
+   {
+      h_mysql = xdlopen(libmysql);
+      if (h_mysql == NULL)
+      {  xprintf("unable to open library %s\n", libmysql);
+         xprintf("%s\n", xerrmsg());
+         return NULL;
+      }
+   }
+
+   sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql));
+   if (sql == NULL)
+         return NULL;
+   sql->mode = mode;
+   sql->res = NULL;
+   sql->query = NULL;
+   sql->nf = mpl_tab_num_flds(dca);
+
+   narg = mpl_tab_num_args(dca);
+   if (narg < 3 )
+      xprintf("MySQL driver: string list too short \n");
+
+   /* get connection string*/
+   dsn = (char *) mpl_tab_get_arg(dca, 2);
+      /* copy connection string*/
+   i = strlen(dsn);
+   i++;
+   arg = xmalloc(i * sizeof(char));
+   strcpy(arg, dsn);
+   /*tokenize connection string*/
+   for (i = 1, keyword = strtok (arg, "="); (keyword != NULL);
+      keyword = strtok (NULL, "="), i++)
+   {
+         value = strtok (NULL, ";");
+      if (value==NULL)
+         {
+            xprintf("db_mysql_open: Missing value for keyword %s\n",
+               keyword);
+            xfree(arg);
+            xfree(sql);
+            return NULL;
+      }
+      if (0 == strcmp(keyword, "Server"))
+            server = value;
+      else if (0 == strcmp(keyword, "Database"))
+             database = value;
+      else if (0 == strcmp(keyword, "UID"))
+             user = value;
+      else if (0 == strcmp(keyword, "PWD"))
+             password = value;
+      else if (0 == strcmp(keyword, "Port"))
+             port = (unsigned int) atol(value);
+   }
+   /* Connect to database */
+   sql->con = dl_mysql_init(NULL);
+  if (!dl_mysql_real_connect(sql->con, server, user, password, database,
+      port, NULL, 0))
+   {
+      xprintf("db_mysql_open: Connect failed\n");
+      xprintf("%s\n", dl_mysql_error(sql->con));
+      xfree(arg);
+      xfree(sql);
+      return NULL;
+   }
+   xfree(arg);
+
+   for(j = 0; sqllines[j+1] != NULL; j++)
+   {  query = (char *) sqllines[j];
+      xprintf("%s\n", query);
+      if (dl_mysql_query(sql->con, query))
+      {
+         xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+         xprintf("%s\n",dl_mysql_error(sql->con));
+         dl_mysql_close(sql->con);
+         xfree(sql);
+         return NULL;
+      }
+   }
+
+   if ( sql->mode == 'R' )
+   {  sql->nf = mpl_tab_num_flds(dca);
+      for(j = 0; sqllines[j] != NULL; j++)
+         arg = (char *) sqllines[j];
+      total = strlen(arg);
+      if (total > 7 && 0 == strncmp(arg, "SELECT ", 7))
+      {
+         total = strlen(arg);
+         query = xmalloc( (total+1) * sizeof(char));
+         strcpy (query, arg);
+      }
+      else
+      {
+         query = db_generate_select_stmt(dca);
+      }
+      xprintf("%s\n", query);
+      if (dl_mysql_query(sql->con, query))
+      {
+         xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+         xprintf("%s\n",dl_mysql_error(sql->con));
+         dl_mysql_close(sql->con);
+         xfree(query);
+         xfree(sql);
+         return NULL;
+      }
+      xfree(query);
+      sql->res = dl_mysql_use_result(sql->con);
+      if (sql->res)
+      {
+         /* create references between query results and table fields*/
+         total = dl_mysql_num_fields(sql->res);
+         if (total > SQL_FIELD_MAX)
+         {  xprintf("db_mysql_open: Too many fields (> %d) in query.\n"
+               "\"%s\"\n", SQL_FIELD_MAX, query);
+            xprintf("%s\n",dl_mysql_error(sql->con));
+            dl_mysql_close(sql->con);
+            xfree(query);
+                 xfree(sql);
+            return NULL;
+         }
+         fields = dl_mysql_fetch_fields(sql->res);
+         for (i = 1; i <= total; i++)
+         {
+               for (j = sql->nf; j >= 1; j--)
+            {
+               if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name)
+                  == 0)
+               break;
+            }
+            sql->ref[i] = j;
+         }
+      }
+      else
+      {
+         if(dl_mysql_field_count(sql->con) == 0)
+            {
+            xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n",
+               query);
+            xprintf("%s\n",dl_mysql_error(sql->con));
+            xfree(query);
+            xfree(sql);
+            return NULL;
+         }
+         else
+         {
+            xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query);
+            xprintf("%s\n",dl_mysql_error(sql->con));
+            xfree(query);
+            xfree(sql);
+            return NULL;
+         }
+      }
+   }
+   else if ( sql->mode == 'W' )
+   {  for(j = 0; sqllines[j] != NULL; j++)
+         arg = (char *) sqllines[j];
+      if (  NULL != strchr(arg, '?') )
+      {
+         total = strlen(arg);
+         query = xmalloc( (total+1) * sizeof(char));
+         strcpy (query, arg);
+         }
+      else
+         query = db_generate_insert_stmt(dca);
+      sql->query = query;
+      xprintf("%s\n", query);
+   }
+   return sql;
+}
+
+int db_mysql_read(TABDCA *dca, void *link)
+{  struct db_mysql *sql;
+   char            buf[255+1];
+   char            **row;
+   unsigned long   *lengths;
+   MYSQL_FIELD     *fields;
+   double          num;
+   int             len;
+   unsigned long   num_fields;
+   int             i;
+
+   sql = (struct db_mysql *) link;
+
+   xassert(sql != NULL);
+   xassert(sql->mode == 'R');
+   if (NULL == sql->res)
+   {
+      xprintf("db_mysql_read: no result set available");
+      return 1;
+   }
+   if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) {
+       return -1; /*EOF*/
+   }
+   lengths = dl_mysql_fetch_lengths(sql->res);
+   fields = dl_mysql_fetch_fields(sql->res);
+   num_fields = dl_mysql_num_fields(sql->res);
+   for (i=1; i <= num_fields; i++)
+   {
+      if (row[i-1] != NULL)
+      {  len = (size_t) lengths[i-1];
+         if (len > 255)
+            len = 255;
+         strncpy(buf, (const char *) row[i-1], len);
+         buf[len] = 0x00;
+         if (0 != (fields[i-1].flags & NUM_FLAG))
+         {  strspx(buf); /* remove spaces*/
+            if (str2num(buf, &num) != 0)
+            {  xprintf("'%s' cannot be converted to a number.\n", buf);
+               return 1;
+            }
+            if (sql->ref[i] > 0)
+               mpl_tab_set_num(dca, sql->ref[i], num);
+         }
+         else
+         {  if (sql->ref[i] > 0)
+               mpl_tab_set_str(dca, sql->ref[i], strtrim(buf));
+         }
+      }
+   }
+   return 0;
+}
+
+int db_mysql_write(TABDCA *dca, void *link)
+{
+   struct db_mysql *sql;
+   char            *part;
+   char            *query;
+   char            *template;
+   char             num[50];
+   int              k;
+   int              len;
+   int              nf;
+
+   sql = (struct db_mysql *) link;
+   xassert(sql != NULL);
+   xassert(sql->mode == 'W');
+
+   len      = strlen(sql->query);
+   template = (char *) xmalloc( (len + 1) * sizeof(char) );
+   strcpy(template, sql->query);
+
+   nf = mpl_tab_num_flds(dca);
+   for (k = 1; k <= nf; k++)
+   {     switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+            len += 20;
+            break;
+         case 'S':
+            len += db_escaped_string_length(mpl_tab_get_str(dca, k));
+            len += 2;
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   query = xmalloc( (len + 1 ) * sizeof(char) );
+   query[0] = 0x00;
+   for (k = 1, part = strtok (template, "?"); (part != NULL);
+      part = strtok (NULL, "?"), k++)
+   {
+      if (k > nf) break;
+      strcat( query, part );
+      switch (mpl_tab_get_type(dca, k))
+      {  case 'N':
+#if 0 /* 02/XI-2010 by xypron */
+            sprintf(num, "%-18g",mpl_tab_get_num(dca, k));
+#else
+            sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k));
+#endif
+            strcat( query, num );
+            break;
+         case 'S':
+            strcat( query, "'");
+            db_escape_string( query + strlen(query),
+               mpl_tab_get_str(dca, k) );
+            strcat( query, "'");
+            break;
+              default:
+                        xassert(dca != dca);
+         }
+   }
+   if (part != NULL)
+      strcat(query, part);
+   if (dl_mysql_query(sql->con, query))
+   {
+      xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query);
+      xprintf("%s\n",dl_mysql_error(sql->con));
+      xfree(query);
+      xfree(template);
+      return 1;
+      }
+
+   xfree(query);
+   xfree(template);
+   return 0;
+   }
+
+int db_mysql_close(TABDCA *dca, void *link)
+{
+   struct db_mysql *sql;
+
+   sql = (struct db_mysql *) link;
+   xassert(sql != NULL);
+   dl_mysql_close(sql->con);
+   if ( sql->mode == 'W' )
+      xfree(sql->query);
+   xfree(sql);
+   dca->link = NULL;
+   return 0;
+}
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpsql.h
===================================================================
--- deps/glpk/src/glpsql.h	(revision 9)
+++ deps/glpk/src/glpsql.h	(revision 9)
@@ -0,0 +1,64 @@
+/* glpsql.h */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Author: Heinrich Schuchardt <heinrich.schuchardt@gmx.de>.
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPSQL_H
+#define GLPSQL_H
+
+#define db_iodbc_open _glp_db_iodbc_open
+void *db_iodbc_open(TABDCA *dca, int mode);
+/* open iODBC database connection */
+
+#define db_iodbc_read _glp_db_iodbc_read
+int db_iodbc_read(TABDCA *dca, void *link);
+/* read data from iODBC */
+
+#define db_iodbc_write _glp_db_iodbc_write
+int db_iodbc_write(TABDCA *dca, void *link);
+/* write data to iODBC */
+
+#define db_iodbc_close _glp_db_iodbc_close
+int db_iodbc_close(TABDCA *dca, void *link);
+/* close iODBC database connection */
+
+#define db_mysql_open _glp_db_mysql_open
+void *db_mysql_open(TABDCA *dca, int mode);
+/* open MySQL database connection */
+
+#define db_mysql_read _glp_db_mysql_read
+int db_mysql_read(TABDCA *dca, void *link);
+/* read data from MySQL */
+
+#define db_mysql_write _glp_db_mysql_write
+int db_mysql_write(TABDCA *dca, void *link);
+/* write data to MySQL */
+
+#define db_mysql_close _glp_db_mysql_close
+int db_mysql_close(TABDCA *dca, void *link);
+/* close MySQL database connection */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpssx.h
===================================================================
--- deps/glpk/src/glpssx.h	(revision 9)
+++ deps/glpk/src/glpssx.h	(revision 9)
@@ -0,0 +1,418 @@
+/* glpssx.h (simplex method, bignum arithmetic) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPSSX_H
+#define GLPSSX_H
+
+#include "glpbfx.h"
+#include "glpenv.h"
+
+typedef struct SSX SSX;
+
+struct SSX
+{     /* simplex solver workspace */
+/*----------------------------------------------------------------------
+// LP PROBLEM DATA
+//
+// It is assumed that LP problem has the following statement:
+//
+//    minimize (or maximize)
+//
+//       z = c[1]*x[1] + ... + c[m+n]*x[m+n] + c[0]                  (1)
+//
+//    subject to equality constraints
+//
+//       x[1] - a[1,1]*x[m+1] - ... - a[1,n]*x[m+n] = 0
+//
+//          .  .  .  .  .  .  .                                      (2)
+//
+//       x[m] - a[m,1]*x[m+1] + ... - a[m,n]*x[m+n] = 0
+//
+//    and bounds of variables
+//
+//         l[1] <= x[1]   <= u[1]
+//
+//          .  .  .  .  .  .  .                                      (3)
+//
+//       l[m+n] <= x[m+n] <= u[m+n]
+//
+// where:
+// x[1], ..., x[m]      - auxiliary variables;
+// x[m+1], ..., x[m+n]  - structural variables;
+// z                    - objective function;
+// c[1], ..., c[m+n]    - coefficients of the objective function;
+// c[0]                 - constant term of the objective function;
+// a[1,1], ..., a[m,n]  - constraint coefficients;
+// l[1], ..., l[m+n]    - lower bounds of variables;
+// u[1], ..., u[m+n]    - upper bounds of variables.
+//
+// Bounds of variables can be finite as well as inifinite. Besides,
+// lower and upper bounds can be equal to each other. So the following
+// five types of variables are possible:
+//
+//    Bounds of variable      Type of variable
+//    -------------------------------------------------
+//    -inf <  x[k] <  +inf    Free (unbounded) variable
+//    l[k] <= x[k] <  +inf    Variable with lower bound
+//    -inf <  x[k] <= u[k]    Variable with upper bound
+//    l[k] <= x[k] <= u[k]    Double-bounded variable
+//    l[k] =  x[k] =  u[k]    Fixed variable
+//
+// Using vector-matrix notations the LP problem (1)-(3) can be written
+// as follows:
+//
+//    minimize (or maximize)
+//
+//       z = c * x + c[0]                                            (4)
+//
+//    subject to equality constraints
+//
+//       xR - A * xS = 0                                             (5)
+//
+//    and bounds of variables
+//
+//       l <= x <= u                                                 (6)
+//
+// where:
+// xR                   - vector of auxiliary variables;
+// xS                   - vector of structural variables;
+// x = (xR, xS)         - vector of all variables;
+// z                    - objective function;
+// c                    - vector of objective coefficients;
+// c[0]                 - constant term of the objective function;
+// A                    - matrix of constraint coefficients (has m rows
+//                        and n columns);
+// l                    - vector of lower bounds of variables;
+// u                    - vector of upper bounds of variables.
+//
+// The simplex method makes no difference between auxiliary and
+// structural variables, so it is convenient to think the system of
+// equality constraints (5) written in a homogeneous form:
+//
+//    (I | -A) * x = 0,                                              (7)
+//
+// where (I | -A) is an augmented (m+n)xm constraint matrix, I is mxm
+// unity matrix whose columns correspond to auxiliary variables, and A
+// is the original mxn constraint matrix whose columns correspond to
+// structural variables. Note that only the matrix A is stored.
+----------------------------------------------------------------------*/
+      int m;
+      /* number of rows (auxiliary variables), m > 0 */
+      int n;
+      /* number of columns (structural variables), n > 0 */
+      int *type; /* int type[1+m+n]; */
+      /* type[0] is not used;
+         type[k], 1 <= k <= m+n, is the type of variable x[k]: */
+#define SSX_FR          0     /* free (unbounded) variable */
+#define SSX_LO          1     /* variable with lower bound */
+#define SSX_UP          2     /* variable with upper bound */
+#define SSX_DB          3     /* double-bounded variable */
+#define SSX_FX          4     /* fixed variable */
+      mpq_t *lb; /* mpq_t lb[1+m+n]; alias: l */
+      /* lb[0] is not used;
+         lb[k], 1 <= k <= m+n, is an lower bound of variable x[k];
+         if x[k] has no lower bound, lb[k] is zero */
+      mpq_t *ub; /* mpq_t ub[1+m+n]; alias: u */
+      /* ub[0] is not used;
+         ub[k], 1 <= k <= m+n, is an upper bound of variable x[k];
+         if x[k] has no upper bound, ub[k] is zero;
+         if x[k] is of fixed type, ub[k] is equal to lb[k] */
+      int dir;
+      /* optimization direction (sense of the objective function): */
+#define SSX_MIN         0     /* minimization */
+#define SSX_MAX         1     /* maximization */
+      mpq_t *coef; /* mpq_t coef[1+m+n]; alias: c */
+      /* coef[0] is a constant term of the objective function;
+         coef[k], 1 <= k <= m+n, is a coefficient of the objective
+         function at variable x[k];
+         note that auxiliary variables also may have non-zero objective
+         coefficients */
+      int *A_ptr; /* int A_ptr[1+n+1]; */
+      int *A_ind; /* int A_ind[A_ptr[n+1]]; */
+      mpq_t *A_val; /* mpq_t A_val[A_ptr[n+1]]; */
+      /* constraint matrix A (see (5)) in storage-by-columns format */
+/*----------------------------------------------------------------------
+// LP BASIS AND CURRENT BASIC SOLUTION
+//
+// The LP basis is defined by the following partition of the augmented
+// constraint matrix (7):
+//
+//    (B | N) = (I | -A) * Q,                                        (8)
+//
+// where B is a mxm non-singular basis matrix whose columns correspond
+// to basic variables xB, N is a mxn matrix whose columns correspond to
+// non-basic variables xN, and Q is a permutation (m+n)x(m+n) matrix.
+//
+// From (7) and (8) it follows that
+//
+//    (I | -A) * x = (I | -A) * Q * Q' * x = (B | N) * (xB, xN),
+//
+// therefore
+//
+//    (xB, xN) = Q' * x,                                             (9)
+//
+// where x is the vector of all variables in the original order, xB is
+// a vector of basic variables, xN is a vector of non-basic variables,
+// Q' = inv(Q) is a matrix transposed to Q.
+//
+// Current values of non-basic variables xN[j], j = 1, ..., n, are not
+// stored; they are defined implicitly by their statuses as follows:
+//
+//    0,             if xN[j] is free variable
+//    lN[j],         if xN[j] is on its lower bound                 (10)
+//    uN[j],         if xN[j] is on its upper bound
+//    lN[j] = uN[j], if xN[j] is fixed variable
+//
+// where lN[j] and uN[j] are lower and upper bounds of xN[j].
+//
+// Current values of basic variables xB[i], i = 1, ..., m, are computed
+// as follows:
+//
+//    beta = - inv(B) * N * xN,                                     (11)
+//
+// where current values of xN are defined by (10).
+//
+// Current values of simplex multipliers pi[i], i = 1, ..., m (which
+// are values of Lagrange multipliers for equality constraints (7) also
+// called shadow prices) are computed as follows:
+//
+//    pi = inv(B') * cB,                                            (12)
+//
+// where B' is a matrix transposed to B, cB is a vector of objective
+// coefficients at basic variables xB.
+//
+// Current values of reduced costs d[j], j = 1, ..., n, (which are
+// values of Langrange multipliers for active inequality constraints
+// corresponding to non-basic variables) are computed as follows:
+//
+//    d = cN - N' * pi,                                             (13)
+//
+// where N' is a matrix transposed to N, cN is a vector of objective
+// coefficients at non-basic variables xN.
+----------------------------------------------------------------------*/
+      int *stat; /* int stat[1+m+n]; */
+      /* stat[0] is not used;
+         stat[k], 1 <= k <= m+n, is the status of variable x[k]: */
+#define SSX_BS          0     /* basic variable */
+#define SSX_NL          1     /* non-basic variable on lower bound */
+#define SSX_NU          2     /* non-basic variable on upper bound */
+#define SSX_NF          3     /* non-basic free variable */
+#define SSX_NS          4     /* non-basic fixed variable */
+      int *Q_row; /* int Q_row[1+m+n]; */
+      /* matrix Q in row-like format;
+         Q_row[0] is not used;
+         Q_row[i] = j means that q[i,j] = 1 */
+      int *Q_col; /* int Q_col[1+m+n]; */
+      /* matrix Q in column-like format;
+         Q_col[0] is not used;
+         Q_col[j] = i means that q[i,j] = 1 */
+      /* if k-th column of the matrix (I | A) is k'-th column of the
+         matrix (B | N), then Q_row[k] = k' and Q_col[k'] = k;
+         if x[k] is xB[i], then Q_row[k] = i and Q_col[i] = k;
+         if x[k] is xN[j], then Q_row[k] = m+j and Q_col[m+j] = k */
+      BFX *binv;
+      /* invertable form of the basis matrix B */
+      mpq_t *bbar; /* mpq_t bbar[1+m]; alias: beta */
+      /* bbar[0] is a value of the objective function;
+         bbar[i], 1 <= i <= m, is a value of basic variable xB[i] */
+      mpq_t *pi; /* mpq_t pi[1+m]; */
+      /* pi[0] is not used;
+         pi[i], 1 <= i <= m, is a simplex multiplier corresponding to
+         i-th row (equality constraint) */
+      mpq_t *cbar; /* mpq_t cbar[1+n]; alias: d */
+      /* cbar[0] is not used;
+         cbar[j], 1 <= j <= n, is a reduced cost of non-basic variable
+         xN[j] */
+/*----------------------------------------------------------------------
+// SIMPLEX TABLE
+//
+// Due to (8) and (9) the system of equality constraints (7) for the
+// current basis can be written as follows:
+//
+//    xB = A~ * xN,                                                 (14)
+//
+// where
+//
+//    A~ = - inv(B) * N                                             (15)
+//
+// is a mxn matrix called the simplex table.
+//
+// The revised simplex method uses only two components of A~, namely,
+// pivot column corresponding to non-basic variable xN[q] chosen to
+// enter the basis, and pivot row corresponding to basic variable xB[p]
+// chosen to leave the basis.
+//
+// Pivot column alfa_q is q-th column of A~, so
+//
+//    alfa_q = A~ * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q],   (16)
+//
+// where N[q] is q-th column of the matrix N.
+//
+// Pivot row alfa_p is p-th row of A~ or, equivalently, p-th column of
+// A~', a matrix transposed to A~, so
+//
+//    alfa_p = A~' * e[p] = - N' * inv(B') * e[p] = - N' * rho_p,   (17)
+//
+// where (*)' means transposition, and
+//
+//    rho_p = inv(B') * e[p],                                       (18)
+//
+// is p-th column of inv(B') or, that is the same, p-th row of inv(B).
+----------------------------------------------------------------------*/
+      int p;
+      /* number of basic variable xB[p], 1 <= p <= m, chosen to leave
+         the basis */
+      mpq_t *rho; /* mpq_t rho[1+m]; */
+      /* p-th row of the inverse inv(B); see (18) */
+      mpq_t *ap; /* mpq_t ap[1+n]; */
+      /* p-th row of the simplex table; see (17) */
+      int q;
+      /* number of non-basic variable xN[q], 1 <= q <= n, chosen to
+         enter the basis */
+      mpq_t *aq; /* mpq_t aq[1+m]; */
+      /* q-th column of the simplex table; see (16) */
+/*--------------------------------------------------------------------*/
+      int q_dir;
+      /* direction in which non-basic variable xN[q] should change on
+         moving to the adjacent vertex of the polyhedron:
+         +1 means that xN[q] increases
+         -1 means that xN[q] decreases */
+      int p_stat;
+      /* non-basic status which should be assigned to basic variable
+         xB[p] when it has left the basis and become xN[q] */
+      mpq_t delta;
+      /* actual change of xN[q] in the adjacent basis (it has the same
+         sign as q_dir) */
+/*--------------------------------------------------------------------*/
+      int it_lim;
+      /* simplex iterations limit; if this value is positive, it is
+         decreased by one each time when one simplex iteration has been
+         performed, and reaching zero value signals the solver to stop
+         the search; negative value means no iterations limit */
+      int it_cnt;
+      /* simplex iterations count; this count is increased by one each
+         time when one simplex iteration has been performed */
+      double tm_lim;
+      /* searching time limit, in seconds; if this value is positive,
+         it is decreased each time when one simplex iteration has been
+         performed by the amount of time spent for the iteration, and
+         reaching zero value signals the solver to stop the search;
+         negative value means no time limit */
+      double out_frq;
+      /* output frequency, in seconds; this parameter specifies how
+         frequently the solver sends information about the progress of
+         the search to the standard output */
+      glp_long tm_beg;
+      /* starting time of the search, in seconds; the total time of the
+         search is the difference between xtime() and tm_beg */
+      glp_long tm_lag;
+      /* the most recent time, in seconds, at which the progress of the
+         the search was displayed */
+};
+
+#define ssx_create            _glp_ssx_create
+#define ssx_factorize         _glp_ssx_factorize
+#define ssx_get_xNj           _glp_ssx_get_xNj
+#define ssx_eval_bbar         _glp_ssx_eval_bbar
+#define ssx_eval_pi           _glp_ssx_eval_pi
+#define ssx_eval_dj           _glp_ssx_eval_dj
+#define ssx_eval_cbar         _glp_ssx_eval_cbar
+#define ssx_eval_rho          _glp_ssx_eval_rho
+#define ssx_eval_row          _glp_ssx_eval_row
+#define ssx_eval_col          _glp_ssx_eval_col
+#define ssx_chuzc             _glp_ssx_chuzc
+#define ssx_chuzr             _glp_ssx_chuzr
+#define ssx_update_bbar       _glp_ssx_update_bbar
+#define ssx_update_pi         _glp_ssx_update_pi
+#define ssx_update_cbar       _glp_ssx_update_cbar
+#define ssx_change_basis      _glp_ssx_change_basis
+#define ssx_delete            _glp_ssx_delete
+
+#define ssx_phase_I           _glp_ssx_phase_I
+#define ssx_phase_II          _glp_ssx_phase_II
+#define ssx_driver            _glp_ssx_driver
+
+SSX *ssx_create(int m, int n, int nnz);
+/* create simplex solver workspace */
+
+int ssx_factorize(SSX *ssx);
+/* factorize the current basis matrix */
+
+void ssx_get_xNj(SSX *ssx, int j, mpq_t x);
+/* determine value of non-basic variable */
+
+void ssx_eval_bbar(SSX *ssx);
+/* compute values of basic variables */
+
+void ssx_eval_pi(SSX *ssx);
+/* compute values of simplex multipliers */
+
+void ssx_eval_dj(SSX *ssx, int j, mpq_t dj);
+/* compute reduced cost of non-basic variable */
+
+void ssx_eval_cbar(SSX *ssx);
+/* compute reduced costs of all non-basic variables */
+
+void ssx_eval_rho(SSX *ssx);
+/* compute p-th row of the inverse */
+
+void ssx_eval_row(SSX *ssx);
+/* compute pivot row of the simplex table */
+
+void ssx_eval_col(SSX *ssx);
+/* compute pivot column of the simplex table */
+
+void ssx_chuzc(SSX *ssx);
+/* choose pivot column */
+
+void ssx_chuzr(SSX *ssx);
+/* choose pivot row */
+
+void ssx_update_bbar(SSX *ssx);
+/* update values of basic variables */
+
+void ssx_update_pi(SSX *ssx);
+/* update simplex multipliers */
+
+void ssx_update_cbar(SSX *ssx);
+/* update reduced costs of non-basic variables */
+
+void ssx_change_basis(SSX *ssx);
+/* change current basis to adjacent one */
+
+void ssx_delete(SSX *ssx);
+/* delete simplex solver workspace */
+
+int ssx_phase_I(SSX *ssx);
+/* find primal feasible solution */
+
+int ssx_phase_II(SSX *ssx);
+/* find optimal solution */
+
+int ssx_driver(SSX *ssx);
+/* base driver to exact simplex method */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glpssx01.c
===================================================================
--- deps/glpk/src/glpssx01.c	(revision 9)
+++ deps/glpk/src/glpssx01.c	(revision 9)
@@ -0,0 +1,839 @@
+/* glpssx01.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpssx.h"
+#define xfault xerror
+
+/*----------------------------------------------------------------------
+// ssx_create - create simplex solver workspace.
+//
+// This routine creates the workspace used by simplex solver routines,
+// and returns a pointer to it.
+//
+// Parameters m, n, and nnz specify, respectively, the number of rows,
+// columns, and non-zero constraint coefficients.
+//
+// This routine only allocates the memory for the workspace components,
+// so the workspace needs to be saturated by data. */
+
+SSX *ssx_create(int m, int n, int nnz)
+{     SSX *ssx;
+      int i, j, k;
+      if (m < 1)
+         xfault("ssx_create: m = %d; invalid number of rows\n", m);
+      if (n < 1)
+         xfault("ssx_create: n = %d; invalid number of columns\n", n);
+      if (nnz < 0)
+         xfault("ssx_create: nnz = %d; invalid number of non-zero const"
+            "raint coefficients\n", nnz);
+      ssx = xmalloc(sizeof(SSX));
+      ssx->m = m;
+      ssx->n = n;
+      ssx->type = xcalloc(1+m+n, sizeof(int));
+      ssx->lb = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 1; k <= m+n; k++) mpq_init(ssx->lb[k]);
+      ssx->ub = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 1; k <= m+n; k++) mpq_init(ssx->ub[k]);
+      ssx->coef = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 0; k <= m+n; k++) mpq_init(ssx->coef[k]);
+      ssx->A_ptr = xcalloc(1+n+1, sizeof(int));
+      ssx->A_ptr[n+1] = nnz+1;
+      ssx->A_ind = xcalloc(1+nnz, sizeof(int));
+      ssx->A_val = xcalloc(1+nnz, sizeof(mpq_t));
+      for (k = 1; k <= nnz; k++) mpq_init(ssx->A_val[k]);
+      ssx->stat = xcalloc(1+m+n, sizeof(int));
+      ssx->Q_row = xcalloc(1+m+n, sizeof(int));
+      ssx->Q_col = xcalloc(1+m+n, sizeof(int));
+      ssx->binv = bfx_create_binv();
+      ssx->bbar = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 0; i <= m; i++) mpq_init(ssx->bbar[i]);
+      ssx->pi = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 1; i <= m; i++) mpq_init(ssx->pi[i]);
+      ssx->cbar = xcalloc(1+n, sizeof(mpq_t));
+      for (j = 1; j <= n; j++) mpq_init(ssx->cbar[j]);
+      ssx->rho = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 1; i <= m; i++) mpq_init(ssx->rho[i]);
+      ssx->ap = xcalloc(1+n, sizeof(mpq_t));
+      for (j = 1; j <= n; j++) mpq_init(ssx->ap[j]);
+      ssx->aq = xcalloc(1+m, sizeof(mpq_t));
+      for (i = 1; i <= m; i++) mpq_init(ssx->aq[i]);
+      mpq_init(ssx->delta);
+      return ssx;
+}
+
+/*----------------------------------------------------------------------
+// ssx_factorize - factorize the current basis matrix.
+//
+// This routine computes factorization of the current basis matrix B
+// and returns the singularity flag. If the matrix B is non-singular,
+// the flag is zero, otherwise non-zero. */
+
+static int basis_col(void *info, int j, int ind[], mpq_t val[])
+{     /* this auxiliary routine provides row indices and numeric values
+         of non-zero elements in j-th column of the matrix B */
+      SSX *ssx = info;
+      int m = ssx->m;
+      int n = ssx->n;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      int k, len, ptr;
+      xassert(1 <= j && j <= m);
+      k = Q_col[j]; /* x[k] = xB[j] */
+      xassert(1 <= k && k <= m+n);
+      /* j-th column of the matrix B is k-th column of the augmented
+         constraint matrix (I | -A) */
+      if (k <= m)
+      {  /* it is a column of the unity matrix I */
+         len = 1, ind[1] = k, mpq_set_si(val[1], 1, 1);
+      }
+      else
+      {  /* it is a column of the original constraint matrix -A */
+         len = 0;
+         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+         {  len++;
+            ind[len] = A_ind[ptr];
+            mpq_neg(val[len], A_val[ptr]);
+         }
+      }
+      return len;
+}
+
+int ssx_factorize(SSX *ssx)
+{     int ret;
+      ret = bfx_factorize(ssx->binv, ssx->m, basis_col, ssx);
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_get_xNj - determine value of non-basic variable.
+//
+// This routine determines the value of non-basic variable xN[j] in the
+// current basic solution defined as follows:
+//
+//    0,             if xN[j] is free variable
+//    lN[j],         if xN[j] is on its lower bound
+//    uN[j],         if xN[j] is on its upper bound
+//    lN[j] = uN[j], if xN[j] is fixed variable
+//
+// where lN[j] and uN[j] are lower and upper bounds of xN[j]. */
+
+void ssx_get_xNj(SSX *ssx, int j, mpq_t x)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      int *stat = ssx->stat;
+      int *Q_col = ssx->Q_col;
+      int k;
+      xassert(1 <= j && j <= n);
+      k = Q_col[m+j]; /* x[k] = xN[j] */
+      xassert(1 <= k && k <= m+n);
+      switch (stat[k])
+      {  case SSX_NL:
+            /* xN[j] is on its lower bound */
+            mpq_set(x, lb[k]); break;
+         case SSX_NU:
+            /* xN[j] is on its upper bound */
+            mpq_set(x, ub[k]); break;
+         case SSX_NF:
+            /* xN[j] is free variable */
+            mpq_set_si(x, 0, 1); break;
+         case SSX_NS:
+            /* xN[j] is fixed variable */
+            mpq_set(x, lb[k]); break;
+         default:
+            xassert(stat != stat);
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_bbar - compute values of basic variables.
+//
+// This routine computes values of basic variables xB in the current
+// basic solution as follows:
+//
+//    beta = - inv(B) * N * xN,
+//
+// where B is the basis matrix, N is the matrix of non-basic columns,
+// xN is a vector of current values of non-basic variables. */
+
+void ssx_eval_bbar(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *coef = ssx->coef;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      int i, j, k, ptr;
+      mpq_t x, temp;
+      mpq_init(x);
+      mpq_init(temp);
+      /* bbar := 0 */
+      for (i = 1; i <= m; i++)
+         mpq_set_si(bbar[i], 0, 1);
+      /* bbar := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n] */
+      for (j = 1; j <= n; j++)
+      {  ssx_get_xNj(ssx, j, x);
+         if (mpq_sgn(x) == 0) continue;
+         k = Q_col[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+         {  /* N[j] is a column of the unity matrix I */
+            mpq_sub(bbar[k], bbar[k], x);
+         }
+         else
+         {  /* N[j] is a column of the original constraint matrix -A */
+            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+            {  mpq_mul(temp, A_val[ptr], x);
+               mpq_add(bbar[A_ind[ptr]], bbar[A_ind[ptr]], temp);
+            }
+         }
+      }
+      /* bbar := inv(B) * bbar */
+      bfx_ftran(ssx->binv, bbar, 0);
+#if 1
+      /* compute value of the objective function */
+      /* bbar[0] := c[0] */
+      mpq_set(bbar[0], coef[0]);
+      /* bbar[0] := bbar[0] + sum{i in B} cB[i] * xB[i] */
+      for (i = 1; i <= m; i++)
+      {  k = Q_col[i]; /* x[k] = xB[i] */
+         if (mpq_sgn(coef[k]) == 0) continue;
+         mpq_mul(temp, coef[k], bbar[i]);
+         mpq_add(bbar[0], bbar[0], temp);
+      }
+      /* bbar[0] := bbar[0] + sum{j in N} cN[j] * xN[j] */
+      for (j = 1; j <= n; j++)
+      {  k = Q_col[m+j]; /* x[k] = xN[j] */
+         if (mpq_sgn(coef[k]) == 0) continue;
+         ssx_get_xNj(ssx, j, x);
+         mpq_mul(temp, coef[k], x);
+         mpq_add(bbar[0], bbar[0], temp);
+      }
+#endif
+      mpq_clear(x);
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_pi - compute values of simplex multipliers.
+//
+// This routine computes values of simplex multipliers (shadow prices)
+// pi in the current basic solution as follows:
+//
+//    pi = inv(B') * cB,
+//
+// where B' is a matrix transposed to the basis matrix B, cB is a vector
+// of objective coefficients at basic variables xB. */
+
+void ssx_eval_pi(SSX *ssx)
+{     int m = ssx->m;
+      mpq_t *coef = ssx->coef;
+      int *Q_col = ssx->Q_col;
+      mpq_t *pi = ssx->pi;
+      int i;
+      /* pi := cB */
+      for (i = 1; i <= m; i++) mpq_set(pi[i], coef[Q_col[i]]);
+      /* pi := inv(B') * cB */
+      bfx_btran(ssx->binv, pi);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_dj - compute reduced cost of non-basic variable.
+//
+// This routine computes reduced cost d[j] of non-basic variable xN[j]
+// in the current basic solution as follows:
+//
+//    d[j] = cN[j] - N[j] * pi,
+//
+// where cN[j] is an objective coefficient at xN[j], N[j] is a column
+// of the augmented constraint matrix (I | -A) corresponding to xN[j],
+// pi is the vector of simplex multipliers (shadow prices). */
+
+void ssx_eval_dj(SSX *ssx, int j, mpq_t dj)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *coef = ssx->coef;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *pi = ssx->pi;
+      int k, ptr, end;
+      mpq_t temp;
+      mpq_init(temp);
+      xassert(1 <= j && j <= n);
+      k = Q_col[m+j]; /* x[k] = xN[j] */
+      xassert(1 <= k && k <= m+n);
+      /* j-th column of the matrix N is k-th column of the augmented
+         constraint matrix (I | -A) */
+      if (k <= m)
+      {  /* it is a column of the unity matrix I */
+         mpq_sub(dj, coef[k], pi[k]);
+      }
+      else
+      {  /* it is a column of the original constraint matrix -A */
+         mpq_set(dj, coef[k]);
+         for (ptr = A_ptr[k-m], end = A_ptr[k-m+1]; ptr < end; ptr++)
+         {  mpq_mul(temp, A_val[ptr], pi[A_ind[ptr]]);
+            mpq_add(dj, dj, temp);
+         }
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_cbar - compute reduced costs of all non-basic variables.
+//
+// This routine computes the vector of reduced costs pi in the current
+// basic solution for all non-basic variables, including fixed ones. */
+
+void ssx_eval_cbar(SSX *ssx)
+{     int n = ssx->n;
+      mpq_t *cbar = ssx->cbar;
+      int j;
+      for (j = 1; j <= n; j++)
+         ssx_eval_dj(ssx, j, cbar[j]);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_rho - compute p-th row of the inverse.
+//
+// This routine computes p-th row of the matrix inv(B), where B is the
+// current basis matrix.
+//
+// p-th row of the inverse is computed using the following formula:
+//
+//    rho = inv(B') * e[p],
+//
+// where B' is a matrix transposed to B, e[p] is a unity vector, which
+// contains one in p-th position. */
+
+void ssx_eval_rho(SSX *ssx)
+{     int m = ssx->m;
+      int p = ssx->p;
+      mpq_t *rho = ssx->rho;
+      int i;
+      xassert(1 <= p && p <= m);
+      /* rho := 0 */
+      for (i = 1; i <= m; i++) mpq_set_si(rho[i], 0, 1);
+      /* rho := e[p] */
+      mpq_set_si(rho[p], 1, 1);
+      /* rho := inv(B') * rho */
+      bfx_btran(ssx->binv, rho);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_row - compute pivot row of the simplex table.
+//
+// This routine computes p-th (pivot) row of the current simplex table
+// A~ = - inv(B) * N using the following formula:
+//
+//    A~[p] = - N' * inv(B') * e[p] = - N' * rho[p],
+//
+// where N' is a matrix transposed to the matrix N, rho[p] is p-th row
+// of the inverse inv(B). */
+
+void ssx_eval_row(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *rho = ssx->rho;
+      mpq_t *ap = ssx->ap;
+      int j, k, ptr;
+      mpq_t temp;
+      mpq_init(temp);
+      for (j = 1; j <= n; j++)
+      {  /* ap[j] := - N'[j] * rho (inner product) */
+         k = Q_col[m+j]; /* x[k] = xN[j] */
+         if (k <= m)
+            mpq_neg(ap[j], rho[k]);
+         else
+         {  mpq_set_si(ap[j], 0, 1);
+            for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+            {  mpq_mul(temp, A_val[ptr], rho[A_ind[ptr]]);
+               mpq_add(ap[j], ap[j], temp);
+            }
+         }
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_eval_col - compute pivot column of the simplex table.
+//
+// This routine computes q-th (pivot) column of the current simplex
+// table A~ = - inv(B) * N using the following formula:
+//
+//    A~[q] = - inv(B) * N[q],
+//
+// where N[q] is q-th column of the matrix N corresponding to chosen
+// non-basic variable xN[q]. */
+
+void ssx_eval_col(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      int i, k, ptr;
+      xassert(1 <= q && q <= n);
+      /* aq := 0 */
+      for (i = 1; i <= m; i++) mpq_set_si(aq[i], 0, 1);
+      /* aq := N[q] */
+      k = Q_col[m+q]; /* x[k] = xN[q] */
+      if (k <= m)
+      {  /* N[q] is a column of the unity matrix I */
+         mpq_set_si(aq[k], 1, 1);
+      }
+      else
+      {  /* N[q] is a column of the original constraint matrix -A */
+         for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+            mpq_neg(aq[A_ind[ptr]], A_val[ptr]);
+      }
+      /* aq := inv(B) * aq */
+      bfx_ftran(ssx->binv, aq, 1);
+      /* aq := - aq */
+      for (i = 1; i <= m; i++) mpq_neg(aq[i], aq[i]);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_chuzc - choose pivot column.
+//
+// This routine chooses non-basic variable xN[q] whose reduced cost
+// indicates possible improving of the objective function to enter it
+// in the basis.
+//
+// Currently the standard (textbook) pricing is used, i.e. that
+// non-basic variable is preferred which has greatest reduced cost (in
+// magnitude).
+//
+// If xN[q] has been chosen, the routine stores its number q and also
+// sets the flag q_dir that indicates direction in which xN[q] has to
+// change (+1 means increasing, -1 means decreasing).
+//
+// If the choice cannot be made, because the current basic solution is
+// dual feasible, the routine sets the number q to 0. */
+
+void ssx_chuzc(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int dir = (ssx->dir == SSX_MIN ? +1 : -1);
+      int *Q_col = ssx->Q_col;
+      int *stat = ssx->stat;
+      mpq_t *cbar = ssx->cbar;
+      int j, k, s, q, q_dir;
+      double best, temp;
+      /* nothing is chosen so far */
+      q = 0, q_dir = 0, best = 0.0;
+      /* look through the list of non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  k = Q_col[m+j]; /* x[k] = xN[j] */
+         s = dir * mpq_sgn(cbar[j]);
+         if ((stat[k] == SSX_NF || stat[k] == SSX_NL) && s < 0 ||
+             (stat[k] == SSX_NF || stat[k] == SSX_NU) && s > 0)
+         {  /* reduced cost of xN[j] indicates possible improving of
+               the objective function */
+            temp = fabs(mpq_get_d(cbar[j]));
+            xassert(temp != 0.0);
+            if (q == 0 || best < temp)
+               q = j, q_dir = - s, best = temp;
+         }
+      }
+      ssx->q = q, ssx->q_dir = q_dir;
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_chuzr - choose pivot row.
+//
+// This routine looks through elements of q-th column of the simplex
+// table and chooses basic variable xB[p] which should leave the basis.
+//
+// The choice is based on the standard (textbook) ratio test.
+//
+// If xB[p] has been chosen, the routine stores its number p and also
+// sets its non-basic status p_stat which should be assigned to xB[p]
+// when it has left the basis and become xN[q].
+//
+// Special case p < 0 means that xN[q] is double-bounded variable and
+// it reaches its opposite bound before any basic variable does that,
+// so the current basis remains unchanged.
+//
+// If the choice cannot be made, because xN[q] can infinitely change in
+// the feasible direction, the routine sets the number p to 0. */
+
+void ssx_chuzr(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      int q_dir = ssx->q_dir;
+      int i, k, s, t, p, p_stat;
+      mpq_t teta, temp;
+      mpq_init(teta);
+      mpq_init(temp);
+      xassert(1 <= q && q <= n);
+      xassert(q_dir == +1 || q_dir == -1);
+      /* nothing is chosen so far */
+      p = 0, p_stat = 0;
+      /* look through the list of basic variables */
+      for (i = 1; i <= m; i++)
+      {  s = q_dir * mpq_sgn(aq[i]);
+         if (s < 0)
+         {  /* xB[i] decreases */
+            k = Q_col[i]; /* x[k] = xB[i] */
+            t = type[k];
+            if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+            {  /* xB[i] has finite lower bound */
+               mpq_sub(temp, bbar[i], lb[k]);
+               mpq_div(temp, temp, aq[i]);
+               mpq_abs(temp, temp);
+               if (p == 0 || mpq_cmp(teta, temp) > 0)
+               {  p = i;
+                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NL);
+                  mpq_set(teta, temp);
+               }
+            }
+         }
+         else if (s > 0)
+         {  /* xB[i] increases */
+            k = Q_col[i]; /* x[k] = xB[i] */
+            t = type[k];
+            if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+            {  /* xB[i] has finite upper bound */
+               mpq_sub(temp, bbar[i], ub[k]);
+               mpq_div(temp, temp, aq[i]);
+               mpq_abs(temp, temp);
+               if (p == 0 || mpq_cmp(teta, temp) > 0)
+               {  p = i;
+                  p_stat = (t == SSX_FX ? SSX_NS : SSX_NU);
+                  mpq_set(teta, temp);
+               }
+            }
+         }
+         /* if something has been chosen and the ratio test indicates
+            exact degeneracy, the search can be finished */
+         if (p != 0 && mpq_sgn(teta) == 0) break;
+      }
+      /* if xN[q] is double-bounded, check if it can reach its opposite
+         bound before any basic variable */
+      k = Q_col[m+q]; /* x[k] = xN[q] */
+      if (type[k] == SSX_DB)
+      {  mpq_sub(temp, ub[k], lb[k]);
+         if (p == 0 || mpq_cmp(teta, temp) > 0)
+         {  p = -1;
+            p_stat = -1;
+            mpq_set(teta, temp);
+         }
+      }
+      ssx->p = p;
+      ssx->p_stat = p_stat;
+      /* if xB[p] has been chosen, determine its actual change in the
+         adjacent basis (it has the same sign as q_dir) */
+      if (p != 0)
+      {  xassert(mpq_sgn(teta) >= 0);
+         if (q_dir > 0)
+            mpq_set(ssx->delta, teta);
+         else
+            mpq_neg(ssx->delta, teta);
+      }
+      mpq_clear(teta);
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_update_bbar - update values of basic variables.
+//
+// This routine recomputes the current values of basic variables for
+// the adjacent basis.
+//
+// The simplex table for the current basis is the following:
+//
+//    xB[i] = sum{j in 1..n} alfa[i,j] * xN[q],  i = 1,...,m
+//
+// therefore
+//
+//    delta xB[i] = alfa[i,q] * delta xN[q],  i = 1,...,m
+//
+// where delta xN[q] = xN.new[q] - xN[q] is the change of xN[q] in the
+// adjacent basis, and delta xB[i] = xB.new[i] - xB[i] is the change of
+// xB[i]. This gives formulae for recomputing values of xB[i]:
+//
+//    xB.new[p] = xN[q] + delta xN[q]
+//
+// (because xN[q] becomes xB[p] in the adjacent basis), and
+//
+//    xB.new[i] = xB[i] + alfa[i,q] * delta xN[q],  i != p
+//
+// for other basic variables. */
+
+void ssx_update_bbar(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *bbar = ssx->bbar;
+      mpq_t *cbar = ssx->cbar;
+      int p = ssx->p;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      int i;
+      mpq_t temp;
+      mpq_init(temp);
+      xassert(1 <= q && q <= n);
+      if (p < 0)
+      {  /* xN[q] is double-bounded and goes to its opposite bound */
+         /* nop */;
+      }
+      else
+      {  /* xN[q] becomes xB[p] in the adjacent basis */
+         /* xB.new[p] = xN[q] + delta xN[q] */
+         xassert(1 <= p && p <= m);
+         ssx_get_xNj(ssx, q, temp);
+         mpq_add(bbar[p], temp, ssx->delta);
+      }
+      /* update values of other basic variables depending on xN[q] */
+      for (i = 1; i <= m; i++)
+      {  if (i == p) continue;
+         /* xB.new[i] = xB[i] + alfa[i,q] * delta xN[q] */
+         if (mpq_sgn(aq[i]) == 0) continue;
+         mpq_mul(temp, aq[i], ssx->delta);
+         mpq_add(bbar[i], bbar[i], temp);
+      }
+#if 1
+      /* update value of the objective function */
+      /* z.new = z + d[q] * delta xN[q] */
+      mpq_mul(temp, cbar[q], ssx->delta);
+      mpq_add(bbar[0], bbar[0], temp);
+#endif
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- ssx_update_pi - update simplex multipliers.
+--
+-- This routine recomputes the vector of simplex multipliers for the
+-- adjacent basis. */
+
+void ssx_update_pi(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *pi = ssx->pi;
+      mpq_t *cbar = ssx->cbar;
+      int p = ssx->p;
+      int q = ssx->q;
+      mpq_t *aq = ssx->aq;
+      mpq_t *rho = ssx->rho;
+      int i;
+      mpq_t new_dq, temp;
+      mpq_init(new_dq);
+      mpq_init(temp);
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+      /* compute d[q] in the adjacent basis */
+      mpq_div(new_dq, cbar[q], aq[p]);
+      /* update the vector of simplex multipliers */
+      for (i = 1; i <= m; i++)
+      {  if (mpq_sgn(rho[i]) == 0) continue;
+         mpq_mul(temp, new_dq, rho[i]);
+         mpq_sub(pi[i], pi[i], temp);
+      }
+      mpq_clear(new_dq);
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_update_cbar - update reduced costs of non-basic variables.
+//
+// This routine recomputes the vector of reduced costs of non-basic
+// variables for the adjacent basis. */
+
+void ssx_update_cbar(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      mpq_t *cbar = ssx->cbar;
+      int p = ssx->p;
+      int q = ssx->q;
+      mpq_t *ap = ssx->ap;
+      int j;
+      mpq_t temp;
+      mpq_init(temp);
+      xassert(1 <= p && p <= m);
+      xassert(1 <= q && q <= n);
+      /* compute d[q] in the adjacent basis */
+      /* d.new[q] = d[q] / alfa[p,q] */
+      mpq_div(cbar[q], cbar[q], ap[q]);
+      /* update reduced costs of other non-basic variables */
+      for (j = 1; j <= n; j++)
+      {  if (j == q) continue;
+         /* d.new[j] = d[j] - (alfa[p,j] / alfa[p,q]) * d[q] */
+         if (mpq_sgn(ap[j]) == 0) continue;
+         mpq_mul(temp, ap[j], cbar[q]);
+         mpq_sub(cbar[j], cbar[j], temp);
+      }
+      mpq_clear(temp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_change_basis - change current basis to adjacent one.
+//
+// This routine changes the current basis to the adjacent one swapping
+// basic variable xB[p] and non-basic variable xN[q]. */
+
+void ssx_change_basis(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      int *stat = ssx->stat;
+      int *Q_row = ssx->Q_row;
+      int *Q_col = ssx->Q_col;
+      int p = ssx->p;
+      int q = ssx->q;
+      int p_stat = ssx->p_stat;
+      int k, kp, kq;
+      if (p < 0)
+      {  /* special case: xN[q] goes to its opposite bound */
+         xassert(1 <= q && q <= n);
+         k = Q_col[m+q]; /* x[k] = xN[q] */
+         xassert(type[k] == SSX_DB);
+         switch (stat[k])
+         {  case SSX_NL:
+               stat[k] = SSX_NU;
+               break;
+            case SSX_NU:
+               stat[k] = SSX_NL;
+               break;
+            default:
+               xassert(stat != stat);
+         }
+      }
+      else
+      {  /* xB[p] leaves the basis, xN[q] enters the basis */
+         xassert(1 <= p && p <= m);
+         xassert(1 <= q && q <= n);
+         kp = Q_col[p];   /* x[kp] = xB[p] */
+         kq = Q_col[m+q]; /* x[kq] = xN[q] */
+         /* check non-basic status of xB[p] which becomes xN[q] */
+         switch (type[kp])
+         {  case SSX_FR:
+               xassert(p_stat == SSX_NF);
+               break;
+            case SSX_LO:
+               xassert(p_stat == SSX_NL);
+               break;
+            case SSX_UP:
+               xassert(p_stat == SSX_NU);
+               break;
+            case SSX_DB:
+               xassert(p_stat == SSX_NL || p_stat == SSX_NU);
+               break;
+            case SSX_FX:
+               xassert(p_stat == SSX_NS);
+               break;
+            default:
+               xassert(type != type);
+         }
+         /* swap xB[p] and xN[q] */
+         stat[kp] = (char)p_stat, stat[kq] = SSX_BS;
+         Q_row[kp] = m+q, Q_row[kq] = p;
+         Q_col[p] = kq, Q_col[m+q] = kp;
+         /* update factorization of the basis matrix */
+         if (bfx_update(ssx->binv, p))
+         {  if (ssx_factorize(ssx))
+               xassert(("Internal error: basis matrix is singular", 0));
+         }
+      }
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_delete - delete simplex solver workspace.
+//
+// This routine deletes the simplex solver workspace freeing all the
+// memory allocated to this object. */
+
+void ssx_delete(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int nnz = ssx->A_ptr[n+1]-1;
+      int i, j, k;
+      xfree(ssx->type);
+      for (k = 1; k <= m+n; k++) mpq_clear(ssx->lb[k]);
+      xfree(ssx->lb);
+      for (k = 1; k <= m+n; k++) mpq_clear(ssx->ub[k]);
+      xfree(ssx->ub);
+      for (k = 0; k <= m+n; k++) mpq_clear(ssx->coef[k]);
+      xfree(ssx->coef);
+      xfree(ssx->A_ptr);
+      xfree(ssx->A_ind);
+      for (k = 1; k <= nnz; k++) mpq_clear(ssx->A_val[k]);
+      xfree(ssx->A_val);
+      xfree(ssx->stat);
+      xfree(ssx->Q_row);
+      xfree(ssx->Q_col);
+      bfx_delete_binv(ssx->binv);
+      for (i = 0; i <= m; i++) mpq_clear(ssx->bbar[i]);
+      xfree(ssx->bbar);
+      for (i = 1; i <= m; i++) mpq_clear(ssx->pi[i]);
+      xfree(ssx->pi);
+      for (j = 1; j <= n; j++) mpq_clear(ssx->cbar[j]);
+      xfree(ssx->cbar);
+      for (i = 1; i <= m; i++) mpq_clear(ssx->rho[i]);
+      xfree(ssx->rho);
+      for (j = 1; j <= n; j++) mpq_clear(ssx->ap[j]);
+      xfree(ssx->ap);
+      for (i = 1; i <= m; i++) mpq_clear(ssx->aq[i]);
+      xfree(ssx->aq);
+      mpq_clear(ssx->delta);
+      xfree(ssx);
+      return;
+}
+
+/* eof */
Index: deps/glpk/src/glpssx02.c
===================================================================
--- deps/glpk/src/glpssx02.c	(revision 9)
+++ deps/glpk/src/glpssx02.c	(revision 9)
@@ -0,0 +1,479 @@
+/* glpssx02.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#include "glpenv.h"
+#include "glpssx.h"
+
+static void show_progress(SSX *ssx, int phase)
+{     /* this auxiliary routine displays information about progress of
+         the search */
+      int i, def = 0;
+      for (i = 1; i <= ssx->m; i++)
+         if (ssx->type[ssx->Q_col[i]] == SSX_FX) def++;
+      xprintf("%s%6d:   %s = %22.15g   (%d)\n", phase == 1 ? " " : "*",
+         ssx->it_cnt, phase == 1 ? "infsum" : "objval",
+         mpq_get_d(ssx->bbar[0]), def);
+#if 0
+      ssx->tm_lag = utime();
+#else
+      ssx->tm_lag = xtime();
+#endif
+      return;
+}
+
+/*----------------------------------------------------------------------
+// ssx_phase_I - find primal feasible solution.
+//
+// This routine implements phase I of the primal simplex method.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - feasible solution found;
+// 1 - problem has no feasible solution;
+// 2 - iterations limit exceeded;
+// 3 - time limit exceeded.
+----------------------------------------------------------------------*/
+
+int ssx_phase_I(SSX *ssx)
+{     int m = ssx->m;
+      int n = ssx->n;
+      int *type = ssx->type;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      mpq_t *coef = ssx->coef;
+      int *A_ptr = ssx->A_ptr;
+      int *A_ind = ssx->A_ind;
+      mpq_t *A_val = ssx->A_val;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      mpq_t *pi = ssx->pi;
+      mpq_t *cbar = ssx->cbar;
+      int *orig_type, orig_dir;
+      mpq_t *orig_lb, *orig_ub, *orig_coef;
+      int i, k, ret;
+      /* save components of the original LP problem, which are changed
+         by the routine */
+      orig_type = xcalloc(1+m+n, sizeof(int));
+      orig_lb = xcalloc(1+m+n, sizeof(mpq_t));
+      orig_ub = xcalloc(1+m+n, sizeof(mpq_t));
+      orig_coef = xcalloc(1+m+n, sizeof(mpq_t));
+      for (k = 1; k <= m+n; k++)
+      {  orig_type[k] = type[k];
+         mpq_init(orig_lb[k]);
+         mpq_set(orig_lb[k], lb[k]);
+         mpq_init(orig_ub[k]);
+         mpq_set(orig_ub[k], ub[k]);
+      }
+      orig_dir = ssx->dir;
+      for (k = 0; k <= m+n; k++)
+      {  mpq_init(orig_coef[k]);
+         mpq_set(orig_coef[k], coef[k]);
+      }
+      /* build an artificial basic solution, which is primal feasible,
+         and also build an auxiliary objective function to minimize the
+         sum of infeasibilities for the original problem */
+      ssx->dir = SSX_MIN;
+      for (k = 0; k <= m+n; k++) mpq_set_si(coef[k], 0, 1);
+      mpq_set_si(bbar[0], 0, 1);
+      for (i = 1; i <= m; i++)
+      {  int t;
+         k = Q_col[i]; /* x[k] = xB[i] */
+         t = type[k];
+         if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+         {  /* in the original problem x[k] has lower bound */
+            if (mpq_cmp(bbar[i], lb[k]) < 0)
+            {  /* which is violated */
+               type[k] = SSX_UP;
+               mpq_set(ub[k], lb[k]);
+               mpq_set_si(lb[k], 0, 1);
+               mpq_set_si(coef[k], -1, 1);
+               mpq_add(bbar[0], bbar[0], ub[k]);
+               mpq_sub(bbar[0], bbar[0], bbar[i]);
+            }
+         }
+         if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+         {  /* in the original problem x[k] has upper bound */
+            if (mpq_cmp(bbar[i], ub[k]) > 0)
+            {  /* which is violated */
+               type[k] = SSX_LO;
+               mpq_set(lb[k], ub[k]);
+               mpq_set_si(ub[k], 0, 1);
+               mpq_set_si(coef[k], +1, 1);
+               mpq_add(bbar[0], bbar[0], bbar[i]);
+               mpq_sub(bbar[0], bbar[0], lb[k]);
+            }
+         }
+      }
+      /* now the initial basic solution should be primal feasible due
+         to changes of bounds of some basic variables, which turned to
+         implicit artifical variables */
+      /* compute simplex multipliers and reduced costs */
+      ssx_eval_pi(ssx);
+      ssx_eval_cbar(ssx);
+      /* display initial progress of the search */
+      show_progress(ssx, 1);
+      /* main loop starts here */
+      for (;;)
+      {  /* display current progress of the search */
+#if 0
+         if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
+#else
+         if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
+#endif
+            show_progress(ssx, 1);
+         /* we do not need to wait until all artificial variables have
+            left the basis */
+         if (mpq_sgn(bbar[0]) == 0)
+         {  /* the sum of infeasibilities is zero, therefore the current
+               solution is primal feasible for the original problem */
+            ret = 0;
+            break;
+         }
+         /* check if the iterations limit has been exhausted */
+         if (ssx->it_lim == 0)
+         {  ret = 2;
+            break;
+         }
+         /* check if the time limit has been exhausted */
+#if 0
+         if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
+#else
+         if (ssx->tm_lim >= 0.0 &&
+             ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
+#endif
+         {  ret = 3;
+            break;
+         }
+         /* choose non-basic variable xN[q] */
+         ssx_chuzc(ssx);
+         /* if xN[q] cannot be chosen, the sum of infeasibilities is
+            minimal but non-zero; therefore the original problem has no
+            primal feasible solution */
+         if (ssx->q == 0)
+         {  ret = 1;
+            break;
+         }
+         /* compute q-th column of the simplex table */
+         ssx_eval_col(ssx);
+         /* choose basic variable xB[p] */
+         ssx_chuzr(ssx);
+         /* the sum of infeasibilities cannot be negative, therefore
+            the auxiliary lp problem cannot have unbounded solution */
+         xassert(ssx->p != 0);
+         /* update values of basic variables */
+         ssx_update_bbar(ssx);
+         if (ssx->p > 0)
+         {  /* compute p-th row of the inverse inv(B) */
+            ssx_eval_rho(ssx);
+            /* compute p-th row of the simplex table */
+            ssx_eval_row(ssx);
+            xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
+            /* update simplex multipliers */
+            ssx_update_pi(ssx);
+            /* update reduced costs of non-basic variables */
+            ssx_update_cbar(ssx);
+         }
+         /* xB[p] is leaving the basis; if it is implicit artificial
+            variable, the corresponding residual vanishes; therefore
+            bounds of this variable should be restored to the original
+            values */
+         if (ssx->p > 0)
+         {  k = Q_col[ssx->p]; /* x[k] = xB[p] */
+            if (type[k] != orig_type[k])
+            {  /* x[k] is implicit artificial variable */
+               type[k] = orig_type[k];
+               mpq_set(lb[k], orig_lb[k]);
+               mpq_set(ub[k], orig_ub[k]);
+               xassert(ssx->p_stat == SSX_NL || ssx->p_stat == SSX_NU);
+               ssx->p_stat = (ssx->p_stat == SSX_NL ? SSX_NU : SSX_NL);
+               if (type[k] == SSX_FX) ssx->p_stat = SSX_NS;
+               /* nullify the objective coefficient at x[k] */
+               mpq_set_si(coef[k], 0, 1);
+               /* since coef[k] has been changed, we need to compute
+                  new reduced cost of x[k], which it will have in the
+                  adjacent basis */
+               /* the formula d[j] = cN[j] - pi' * N[j] is used (note
+                  that the vector pi is not changed, because it depends
+                  on objective coefficients at basic variables, but in
+                  the adjacent basis, for which the vector pi has been
+                  just recomputed, x[k] is non-basic) */
+               if (k <= m)
+               {  /* x[k] is auxiliary variable */
+                  mpq_neg(cbar[ssx->q], pi[k]);
+               }
+               else
+               {  /* x[k] is structural variable */
+                  int ptr;
+                  mpq_t temp;
+                  mpq_init(temp);
+                  mpq_set_si(cbar[ssx->q], 0, 1);
+                  for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++)
+                  {  mpq_mul(temp, pi[A_ind[ptr]], A_val[ptr]);
+                     mpq_add(cbar[ssx->q], cbar[ssx->q], temp);
+                  }
+                  mpq_clear(temp);
+               }
+            }
+         }
+         /* jump to the adjacent vertex of the polyhedron */
+         ssx_change_basis(ssx);
+         /* one simplex iteration has been performed */
+         if (ssx->it_lim > 0) ssx->it_lim--;
+         ssx->it_cnt++;
+      }
+      /* display final progress of the search */
+      show_progress(ssx, 1);
+      /* restore components of the original problem, which were changed
+         by the routine */
+      for (k = 1; k <= m+n; k++)
+      {  type[k] = orig_type[k];
+         mpq_set(lb[k], orig_lb[k]);
+         mpq_clear(orig_lb[k]);
+         mpq_set(ub[k], orig_ub[k]);
+         mpq_clear(orig_ub[k]);
+      }
+      ssx->dir = orig_dir;
+      for (k = 0; k <= m+n; k++)
+      {  mpq_set(coef[k], orig_coef[k]);
+         mpq_clear(orig_coef[k]);
+      }
+      xfree(orig_type);
+      xfree(orig_lb);
+      xfree(orig_ub);
+      xfree(orig_coef);
+      /* return to the calling program */
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_phase_II - find optimal solution.
+//
+// This routine implements phase II of the primal simplex method.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - optimal solution found;
+// 1 - problem has unbounded solution;
+// 2 - iterations limit exceeded;
+// 3 - time limit exceeded.
+----------------------------------------------------------------------*/
+
+int ssx_phase_II(SSX *ssx)
+{     int ret;
+      /* display initial progress of the search */
+      show_progress(ssx, 2);
+      /* main loop starts here */
+      for (;;)
+      {  /* display current progress of the search */
+#if 0
+         if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001)
+#else
+         if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001)
+#endif
+            show_progress(ssx, 2);
+         /* check if the iterations limit has been exhausted */
+         if (ssx->it_lim == 0)
+         {  ret = 2;
+            break;
+         }
+         /* check if the time limit has been exhausted */
+#if 0
+         if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg)
+#else
+         if (ssx->tm_lim >= 0.0 &&
+             ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg))
+#endif
+         {  ret = 3;
+            break;
+         }
+         /* choose non-basic variable xN[q] */
+         ssx_chuzc(ssx);
+         /* if xN[q] cannot be chosen, the current basic solution is
+            dual feasible and therefore optimal */
+         if (ssx->q == 0)
+         {  ret = 0;
+            break;
+         }
+         /* compute q-th column of the simplex table */
+         ssx_eval_col(ssx);
+         /* choose basic variable xB[p] */
+         ssx_chuzr(ssx);
+         /* if xB[p] cannot be chosen, the problem has no dual feasible
+            solution (i.e. unbounded) */
+         if (ssx->p == 0)
+         {  ret = 1;
+            break;
+         }
+         /* update values of basic variables */
+         ssx_update_bbar(ssx);
+         if (ssx->p > 0)
+         {  /* compute p-th row of the inverse inv(B) */
+            ssx_eval_rho(ssx);
+            /* compute p-th row of the simplex table */
+            ssx_eval_row(ssx);
+            xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0);
+#if 0
+            /* update simplex multipliers */
+            ssx_update_pi(ssx);
+#endif
+            /* update reduced costs of non-basic variables */
+            ssx_update_cbar(ssx);
+         }
+         /* jump to the adjacent vertex of the polyhedron */
+         ssx_change_basis(ssx);
+         /* one simplex iteration has been performed */
+         if (ssx->it_lim > 0) ssx->it_lim--;
+         ssx->it_cnt++;
+      }
+      /* display final progress of the search */
+      show_progress(ssx, 2);
+      /* return to the calling program */
+      return ret;
+}
+
+/*----------------------------------------------------------------------
+// ssx_driver - base driver to exact simplex method.
+//
+// This routine is a base driver to a version of the primal simplex
+// method using exact (bignum) arithmetic.
+//
+// On exit the routine returns one of the following codes:
+//
+// 0 - optimal solution found;
+// 1 - problem has no feasible solution;
+// 2 - problem has unbounded solution;
+// 3 - iterations limit exceeded (phase I);
+// 4 - iterations limit exceeded (phase II);
+// 5 - time limit exceeded (phase I);
+// 6 - time limit exceeded (phase II);
+// 7 - initial basis matrix is exactly singular.
+----------------------------------------------------------------------*/
+
+int ssx_driver(SSX *ssx)
+{     int m = ssx->m;
+      int *type = ssx->type;
+      mpq_t *lb = ssx->lb;
+      mpq_t *ub = ssx->ub;
+      int *Q_col = ssx->Q_col;
+      mpq_t *bbar = ssx->bbar;
+      int i, k, ret;
+      ssx->tm_beg = xtime();
+      /* factorize the initial basis matrix */
+      if (ssx_factorize(ssx))
+      {  xprintf("Initial basis matrix is singular\n");
+         ret = 7;
+         goto done;
+      }
+      /* compute values of basic variables */
+      ssx_eval_bbar(ssx);
+      /* check if the initial basic solution is primal feasible */
+      for (i = 1; i <= m; i++)
+      {  int t;
+         k = Q_col[i]; /* x[k] = xB[i] */
+         t = type[k];
+         if (t == SSX_LO || t == SSX_DB || t == SSX_FX)
+         {  /* x[k] has lower bound */
+            if (mpq_cmp(bbar[i], lb[k]) < 0)
+            {  /* which is violated */
+               break;
+            }
+         }
+         if (t == SSX_UP || t == SSX_DB || t == SSX_FX)
+         {  /* x[k] has upper bound */
+            if (mpq_cmp(bbar[i], ub[k]) > 0)
+            {  /* which is violated */
+               break;
+            }
+         }
+      }
+      if (i > m)
+      {  /* no basic variable violates its bounds */
+         ret = 0;
+         goto skip;
+      }
+      /* phase I: find primal feasible solution */
+      ret = ssx_phase_I(ssx);
+      switch (ret)
+      {  case 0:
+            ret = 0;
+            break;
+         case 1:
+            xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n");
+            ret = 1;
+            break;
+         case 2:
+            xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 3;
+            break;
+         case 3:
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 5;
+            break;
+         default:
+            xassert(ret != ret);
+      }
+      /* compute values of basic variables (actually only the objective
+         value needs to be computed) */
+      ssx_eval_bbar(ssx);
+skip: /* compute simplex multipliers */
+      ssx_eval_pi(ssx);
+      /* compute reduced costs of non-basic variables */
+      ssx_eval_cbar(ssx);
+      /* if phase I failed, do not start phase II */
+      if (ret != 0) goto done;
+      /* phase II: find optimal solution */
+      ret = ssx_phase_II(ssx);
+      switch (ret)
+      {  case 0:
+            xprintf("OPTIMAL SOLUTION FOUND\n");
+            ret = 0;
+            break;
+         case 1:
+            xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n");
+            ret = 2;
+            break;
+         case 2:
+            xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 4;
+            break;
+         case 3:
+            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
+            ret = 6;
+            break;
+         default:
+            xassert(ret != ret);
+      }
+done: /* decrease the time limit by the spent amount of time */
+      if (ssx->tm_lim >= 0.0)
+#if 0
+      {  ssx->tm_lim -= utime() - ssx->tm_beg;
+#else
+      {  ssx->tm_lim -= xdifftime(xtime(), ssx->tm_beg);
+#endif
+         if (ssx->tm_lim < 0.0) ssx->tm_lim = 0.0;
+      }
+      return ret;
+}
+
+/* eof */
Index: deps/glpk/src/glpstd.h
===================================================================
--- deps/glpk/src/glpstd.h	(revision 9)
+++ deps/glpk/src/glpstd.h	(revision 9)
@@ -0,0 +1,43 @@
+/* glpstd.h (standard C headers) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPSTD_H
+#define GLPSTD_H
+
+#include <ctype.h>
+#include <errno.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#endif
+
+/* eof */
Index: deps/glpk/src/glptsp.c
===================================================================
--- deps/glpk/src/glptsp.c	(revision 9)
+++ deps/glpk/src/glptsp.c	(revision 9)
@@ -0,0 +1,667 @@
+/* glptsp.c */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#define _GLPSTD_ERRNO
+#define _GLPSTD_STDIO
+#include "glpenv.h"
+#include "glptsp.h"
+#define xfault xerror
+
+/*----------------------------------------------------------------------
+-- tsp_read_data - read TSP instance data.
+--
+-- *Synopsis*
+--
+-- #include "glptsp.h"
+-- TSP *tsp_read_data(char *fname);
+--
+-- *Description*
+--
+-- The routine tsp_read_data reads a TSP (or related problem) instance
+-- data from the text file, whose name is the character string fname.
+--
+-- For detailed description of the format recognized by the routine see
+-- the report: G.Reinelt, TSPLIB 95.
+--
+-- *Returns*
+--
+-- If no error occurred, the routine tsp_read_data returns a pointer to
+-- the TSP instance data block, which contains loaded data. In the case
+-- of error the routine prints an error message and returns NULL. */
+
+struct dsa
+{     /* dynamic storage area used by the routine tsp_read_data */
+      char *fname;
+      /* name of the input text file */
+      FILE *fp;
+      /* stream assigned to the input text file */
+      int seqn;
+      /* line sequential number */
+      int c;
+      /* current character */
+      char token[255+1];
+      /* current token */
+};
+
+static int get_char(struct dsa *dsa)
+{     dsa->c = fgetc(dsa->fp);
+      if (ferror(dsa->fp))
+      {  xprintf("%s:%d: read error - %s\n",
+            dsa->fname, dsa->seqn, strerror(errno));
+         return 1;
+      }
+      if (feof(dsa->fp))
+         dsa->c = EOF;
+      else if (dsa->c == '\n')
+         dsa->seqn++;
+      else if (isspace(dsa->c))
+         dsa->c = ' ';
+      else if (iscntrl(dsa->c))
+      {  xprintf("%s:%d: invalid control character 0x%02X\n",
+            dsa->fname, dsa->seqn, dsa->c);
+         return 1;
+      }
+      return 0;
+}
+
+static int skip_spaces(struct dsa *dsa, int across)
+{     while (dsa->c == ' ' || (across && dsa->c == '\n'))
+         if (get_char(dsa)) return 1;
+      return 0;
+}
+
+static int scan_keyword(struct dsa *dsa)
+{     int len = 0;
+      if (skip_spaces(dsa, 0)) return 1;
+      dsa->token[0] = '\0';
+      while (isalnum(dsa->c) || dsa->c == '_')
+      {  if (len == 31)
+         {  xprintf("%s:%d: keyword `%s...' too long\n", dsa->fname,
+               dsa->seqn, dsa->token);
+            return 1;
+         }
+         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
+         if (get_char(dsa)) return 1;
+      }
+      if (len == 0)
+      {  xprintf("%s:%d: missing keyword\n", dsa->fname, dsa->seqn);
+         return 1;
+      }
+      return 0;
+}
+
+static int check_colon(struct dsa *dsa)
+{     if (skip_spaces(dsa, 0)) return 1;
+      if (dsa->c != ':')
+      {  xprintf("%s:%d: missing colon after `%s'\n", dsa->fname,
+            dsa->seqn, dsa->token);
+         return 1;
+      }
+      if (get_char(dsa)) return 1;
+      return 0;
+}
+
+static int scan_token(struct dsa *dsa, int across)
+{     int len = 0;
+      if (skip_spaces(dsa, across)) return 1;
+      dsa->token[0] = '\0';
+      while (!(dsa->c == EOF || dsa->c == '\n' || dsa->c == ' '))
+      {  if (len == 255)
+         {  dsa->token[31] = '\0';
+            xprintf("%s:%d: token `%s...' too long\n", dsa->fname,
+               dsa->seqn, dsa->token);
+            return 1;
+         }
+         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
+         if (get_char(dsa)) return 1;
+      }
+      return 0;
+}
+
+static int check_newline(struct dsa *dsa)
+{     if (skip_spaces(dsa, 0)) return 1;
+      if (!(dsa->c == EOF || dsa->c == '\n'))
+      {  xprintf("%s:%d: extra symbols detected\n", dsa->fname,
+            dsa->seqn);
+         return 1;
+      }
+      if (get_char(dsa)) return 1;
+      return 0;
+}
+
+static int scan_comment(struct dsa *dsa)
+{     int len = 0;
+      if (skip_spaces(dsa, 0)) return 1;
+      dsa->token[0] = '\0';
+      while (!(dsa->c == EOF || dsa->c == '\n'))
+      {  if (len == 255)
+         {  xprintf("%s:%d: comment too long\n", dsa->fname, dsa->seqn)
+               ;
+            return 1;
+         }
+         dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0';
+         if (get_char(dsa)) return 1;
+      }
+      return 0;
+}
+
+static int scan_integer(struct dsa *dsa, int across, int *val)
+{     if (scan_token(dsa, across)) return 1;
+      if (strlen(dsa->token) == 0)
+      {  xprintf("%s:%d: missing integer\n", dsa->fname, dsa->seqn);
+         return 1;
+      }
+      if (str2int(dsa->token, val))
+      {  xprintf("%s:%d: integer `%s' invalid\n", dsa->fname, dsa->seqn
+            , dsa->token);
+         return 1;
+      }
+      return 0;
+}
+
+static int scan_number(struct dsa *dsa, int across, double *val)
+{     if (scan_token(dsa, across)) return 1;
+      if (strlen(dsa->token) == 0)
+      {  xprintf("%s:%d: missing number\n", dsa->fname, dsa->seqn);
+         return 1;
+      }
+      if (str2num(dsa->token, val))
+      {  xprintf("%s:%d: number `%s' invalid\n", dsa->fname, dsa->seqn,
+            dsa->token);
+         return 1;
+      }
+      return 0;
+}
+
+TSP *tsp_read_data(char *fname)
+{     struct dsa _dsa, *dsa = &_dsa;
+      TSP *tsp = NULL;
+      dsa->fname = fname;
+      xprintf("tsp_read_data: reading TSP data from `%s'...\n",
+         dsa->fname);
+      dsa->fp = fopen(dsa->fname, "r");
+      if (dsa->fp == NULL)
+      {  xprintf("tsp_read_data: unable to open `%s' - %s\n",
+            dsa->fname, strerror(errno));
+         goto fail;
+      }
+      tsp = xmalloc(sizeof(TSP));
+      tsp->name = NULL;
+      tsp->type = TSP_UNDEF;
+      tsp->comment = NULL;
+      tsp->dimension = 0;
+      tsp->edge_weight_type = TSP_UNDEF;
+      tsp->edge_weight_format = TSP_UNDEF;
+      tsp->display_data_type = TSP_UNDEF;
+      tsp->node_x_coord = NULL;
+      tsp->node_y_coord = NULL;
+      tsp->dply_x_coord = NULL;
+      tsp->dply_y_coord = NULL;
+      tsp->tour = NULL;
+      tsp->edge_weight = NULL;
+      dsa->seqn = 1;
+      if (get_char(dsa)) goto fail;
+loop: if (scan_keyword(dsa)) goto fail;
+      if (strcmp(dsa->token, "NAME") == 0)
+      {  if (tsp->name != NULL)
+         {  xprintf("%s:%d: NAME entry multiply defined\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_token(dsa, 0)) goto fail;
+         if (strlen(dsa->token) == 0)
+         {  xprintf("%s:%d: NAME entry incomplete\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         tsp->name = xmalloc(strlen(dsa->token) + 1);
+         strcpy(tsp->name, dsa->token);
+         xprintf("tsp_read_data: NAME: %s\n", tsp->name);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "TYPE") == 0)
+      {  if (tsp->type != TSP_UNDEF)
+         {  xprintf("%s:%d: TYPE entry multiply defined\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "TSP") == 0)
+            tsp->type = TSP_TSP;
+         else if (strcmp(dsa->token, "ATSP") == 0)
+            tsp->type = TSP_ATSP;
+         else if (strcmp(dsa->token, "TOUR") == 0)
+            tsp->type = TSP_TOUR;
+         else
+         {  xprintf("%s:%d: data type `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: TYPE: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "COMMENT") == 0)
+      {  if (tsp->comment != NULL)
+         {  xprintf("%s:%d: COMMENT entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_comment(dsa)) goto fail;
+         tsp->comment = xmalloc(strlen(dsa->token) + 1);
+         strcpy(tsp->comment, dsa->token);
+         xprintf("tsp_read_data: COMMENT: %s\n", tsp->comment);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "DIMENSION") == 0)
+      {  if (tsp->dimension != 0)
+         {  xprintf("%s:%d: DIMENSION entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_integer(dsa, 0, &tsp->dimension)) goto fail;
+         if (tsp->dimension < 1)
+         {  xprintf("%s:%d: invalid dimension\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         xprintf("tsp_read_data: DIMENSION: %d\n", tsp->dimension);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EDGE_WEIGHT_TYPE") == 0)
+      {  if (tsp->edge_weight_type != TSP_UNDEF)
+         {  xprintf("%s:%d: EDGE_WEIGHT_TYPE entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "GEO") == 0)
+            tsp->edge_weight_type = TSP_GEO;
+         else if (strcmp(dsa->token, "EUC_2D") == 0)
+            tsp->edge_weight_type = TSP_EUC_2D;
+         else if (strcmp(dsa->token, "ATT") == 0)
+            tsp->edge_weight_type = TSP_ATT;
+         else if (strcmp(dsa->token, "EXPLICIT") == 0)
+            tsp->edge_weight_type = TSP_EXPLICIT;
+         else if (strcmp(dsa->token, "CEIL_2D") == 0)
+            tsp->edge_weight_type = TSP_CEIL_2D;
+         else
+         {  xprintf("%s:%d: edge weight type `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: EDGE_WEIGHT_TYPE: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EDGE_WEIGHT_FORMAT") == 0)
+      {  if (tsp->edge_weight_format != TSP_UNDEF)
+         {  xprintf(
+               "%s:%d: EDGE_WEIGHT_FORMAT entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "UPPER_ROW") == 0)
+            tsp->edge_weight_format = TSP_UPPER_ROW;
+         else if (strcmp(dsa->token, "FULL_MATRIX") == 0)
+            tsp->edge_weight_format = TSP_FULL_MATRIX;
+         else if (strcmp(dsa->token, "FUNCTION") == 0)
+            tsp->edge_weight_format = TSP_FUNCTION;
+         else if (strcmp(dsa->token, "LOWER_DIAG_ROW") == 0)
+            tsp->edge_weight_format = TSP_LOWER_DIAG_ROW;
+         else
+         {  xprintf("%s:%d: edge weight format `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: EDGE_WEIGHT_FORMAT: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "DISPLAY_DATA_TYPE") == 0)
+      {  if (tsp->display_data_type != TSP_UNDEF)
+         {  xprintf("%s:%d: DISPLAY_DATA_TYPE entry multiply defined\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_colon(dsa)) goto fail;
+         if (scan_keyword(dsa)) goto fail;
+         if (strcmp(dsa->token, "COORD_DISPLAY") == 0)
+            tsp->display_data_type = TSP_COORD_DISPLAY;
+         else if (strcmp(dsa->token, "TWOD_DISPLAY") == 0)
+            tsp->display_data_type = TSP_TWOD_DISPLAY;
+         else
+         {  xprintf("%s:%d: display data type `%s' not recognized\n",
+               dsa->fname, dsa->seqn, dsa->token);
+            goto fail;
+         }
+         xprintf("tsp_read_data: DISPLAY_DATA_TYPE: %s\n", dsa->token);
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "NODE_COORD_SECTION") == 0)
+      {  int n = tsp->dimension, k, node;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->node_x_coord != NULL)
+         {  xprintf("%s:%d: NODE_COORD_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->node_x_coord = xcalloc(1+n, sizeof(double));
+         tsp->node_y_coord = xcalloc(1+n, sizeof(double));
+         for (node = 1; node <= n; node++)
+            tsp->node_x_coord[node] = tsp->node_y_coord[node] = DBL_MAX;
+         for (k = 1; k <= n; k++)
+         {  if (scan_integer(dsa, 0, &node)) goto fail;
+            if (!(1 <= node && node <= n))
+            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
+                  dsa->seqn, node);
+               goto fail;
+            }
+            if (tsp->node_x_coord[node] != DBL_MAX)
+            {  xprintf("%s:%d: node number %d multiply specified\n",
+                  dsa->fname, dsa->seqn, node);
+               goto fail;
+            }
+            if (scan_number(dsa, 0, &tsp->node_x_coord[node]))
+               goto fail;
+            if (scan_number(dsa, 0, &tsp->node_y_coord[node]))
+               goto fail;
+            if (check_newline(dsa)) goto fail;
+         }
+      }
+      else if (strcmp(dsa->token, "DISPLAY_DATA_SECTION") == 0)
+      {  int n = tsp->dimension, k, node;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->dply_x_coord != NULL)
+         {  xprintf("%s:%d: DISPLAY_DATA_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->dply_x_coord = xcalloc(1+n, sizeof(double));
+         tsp->dply_y_coord = xcalloc(1+n, sizeof(double));
+         for (node = 1; node <= n; node++)
+            tsp->dply_x_coord[node] = tsp->dply_y_coord[node] = DBL_MAX;
+         for (k = 1; k <= n; k++)
+         {  if (scan_integer(dsa, 0, &node)) goto fail;
+            if (!(1 <= node && node <= n))
+            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
+                  dsa->seqn, node);
+               goto fail;
+            }
+            if (tsp->dply_x_coord[node] != DBL_MAX)
+            {  xprintf("%s:%d: node number %d multiply specified\n",
+                  dsa->fname, dsa->seqn, node);
+               goto fail;
+            }
+            if (scan_number(dsa, 0, &tsp->dply_x_coord[node]))
+               goto fail;
+            if (scan_number(dsa, 0, &tsp->dply_y_coord[node]))
+               goto fail;
+            if (check_newline(dsa)) goto fail;
+         }
+      }
+      else if (strcmp(dsa->token, "TOUR_SECTION") == 0)
+      {  int n = tsp->dimension, k, node;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->tour != NULL)
+         {  xprintf("%s:%d: TOUR_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->tour = xcalloc(1+n, sizeof(int));
+         for (k = 1; k <= n; k++)
+         {  if (scan_integer(dsa, 1, &node)) goto fail;
+            if (!(1 <= node && node <= n))
+            {  xprintf("%s:%d: invalid node number %d\n", dsa->fname,
+                  dsa->seqn, node);
+               goto fail;
+            }
+            tsp->tour[k] = node;
+         }
+         if (scan_integer(dsa, 1, &node)) goto fail;
+         if (node != -1)
+         {  xprintf("%s:%d: extra node(s) detected\n", dsa->fname,
+               dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EDGE_WEIGHT_SECTION") == 0)
+      {  int n = tsp->dimension, i, j, temp;
+         if (n == 0)
+         {  xprintf("%s:%d: DIMENSION entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->edge_weight_format == TSP_UNDEF)
+         {  xprintf("%s:%d: EDGE_WEIGHT_FORMAT entry not specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (tsp->edge_weight != NULL)
+         {  xprintf("%s:%d: EDGE_WEIGHT_SECTION multiply specified\n",
+               dsa->fname, dsa->seqn);
+            goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+         tsp->edge_weight = xcalloc(1+n*n, sizeof(int));
+         switch (tsp->edge_weight_format)
+         {  case TSP_FULL_MATRIX:
+               for (i = 1; i <= n; i++)
+               {  for (j = 1; j <= n; j++)
+                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
+                     tsp->edge_weight[(i - 1) * n + j] = temp;
+                  }
+               }
+               break;
+            case TSP_UPPER_ROW:
+               for (i = 1; i <= n; i++)
+               {  tsp->edge_weight[(i - 1) * n + i] = 0;
+                  for (j = i + 1; j <= n; j++)
+                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
+                     tsp->edge_weight[(i - 1) * n + j] = temp;
+                     tsp->edge_weight[(j - 1) * n + i] = temp;
+                  }
+               }
+               break;
+            case TSP_LOWER_DIAG_ROW:
+               for (i = 1; i <= n; i++)
+               {  for (j = 1; j <= i; j++)
+                  {  if (scan_integer(dsa, 1, &temp)) goto fail;
+                     tsp->edge_weight[(i - 1) * n + j] = temp;
+                     tsp->edge_weight[(j - 1) * n + i] = temp;
+                  }
+               }
+               break;
+            default:
+               goto fail;
+         }
+         if (check_newline(dsa)) goto fail;
+      }
+      else if (strcmp(dsa->token, "EOF") == 0)
+      {  if (check_newline(dsa)) goto fail;
+         goto done;
+      }
+      else
+      {  xprintf("%s:%d: keyword `%s' not recognized\n", dsa->fname,
+            dsa->seqn, dsa->token);
+         goto fail;
+      }
+      goto loop;
+done: xprintf("tsp_read_data: %d lines were read\n", dsa->seqn-1);
+      fclose(dsa->fp);
+      return tsp;
+fail: if (tsp != NULL)
+      {  if (tsp->name != NULL) xfree(tsp->name);
+         if (tsp->comment != NULL) xfree(tsp->comment);
+         if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
+         if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
+         if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
+         if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
+         if (tsp->tour != NULL) xfree(tsp->tour);
+         if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
+         xfree(tsp);
+      }
+      if (dsa->fp != NULL) fclose(dsa->fp);
+      return NULL;
+}
+
+/*----------------------------------------------------------------------
+-- tsp_free_data - free TSP instance data.
+--
+-- *Synopsis*
+--
+-- #include "glptsp.h"
+-- void tsp_free_data(TSP *tsp);
+--
+-- *Description*
+--
+-- The routine tsp_free_data frees all the memory allocated to the TSP
+-- instance data block, which the parameter tsp points to. */
+
+void tsp_free_data(TSP *tsp)
+{     if (tsp->name != NULL) xfree(tsp->name);
+      if (tsp->comment != NULL) xfree(tsp->comment);
+      if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord);
+      if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord);
+      if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord);
+      if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord);
+      if (tsp->tour != NULL) xfree(tsp->tour);
+      if (tsp->edge_weight != NULL) xfree(tsp->edge_weight);
+      xfree(tsp);
+      return;
+}
+
+/*----------------------------------------------------------------------
+-- tsp_distance - compute distance between two nodes.
+--
+-- *Synopsis*
+--
+-- #include "glptsp.h"
+-- int tsp_distance(TSP *tsp, int i, int j);
+--
+-- *Description*
+--
+-- The routine tsp_distance computes the distance between i-th and j-th
+-- nodes for the TSP instance, which tsp points to.
+--
+-- *Returns*
+--
+-- The routine tsp_distance returns the computed distance. */
+
+#define nint(x) ((int)((x) + 0.5))
+
+static double rad(double x)
+{     /* convert input coordinate to longitude/latitude, in radians */
+      double pi = 3.141592, deg, min;
+      deg = (int)x;
+      min = x - deg;
+      return pi * (deg + 5.0 * min / 3.0) / 180.0;
+}
+
+int tsp_distance(TSP *tsp, int i, int j)
+{     int n = tsp->dimension, dij;
+      if (!(tsp->type == TSP_TSP || tsp->type == TSP_ATSP))
+         xfault("tsp_distance: invalid TSP instance\n");
+      if (!(1 <= i && i <= n && 1 <= j && j <= n))
+         xfault("tsp_distance: node number out of range\n");
+      switch (tsp->edge_weight_type)
+      {  case TSP_UNDEF:
+            xfault("tsp_distance: edge weight type not specified\n");
+         case TSP_EXPLICIT:
+            if (tsp->edge_weight == NULL)
+               xfault("tsp_distance: edge weights not specified\n");
+            dij = tsp->edge_weight[(i - 1) * n + j];
+            break;
+         case TSP_EUC_2D:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  double xd, yd;
+               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
+               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
+               dij = nint(sqrt(xd * xd + yd * yd));
+            }
+            break;
+         case TSP_CEIL_2D:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  double xd, yd;
+               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
+               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
+               dij = (int)ceil(sqrt(xd * xd + yd * yd));
+            }
+            break;
+         case TSP_GEO:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  double rrr = 6378.388;
+               double latitude_i = rad(tsp->node_x_coord[i]);
+               double latitude_j = rad(tsp->node_x_coord[j]);
+               double longitude_i = rad(tsp->node_y_coord[i]);
+               double longitude_j = rad(tsp->node_y_coord[j]);
+               double q1 = cos(longitude_i - longitude_j);
+               double q2 = cos(latitude_i - latitude_j);
+               double q3 = cos(latitude_i + latitude_j);
+               dij = (int)(rrr * acos(0.5 * ((1.0 + q1) * q2 -
+                  (1.0 - q1) *q3)) + 1.0);
+            }
+            break;
+         case TSP_ATT:
+            if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL)
+               xfault("tsp_distance: node coordinates not specified\n");
+            {  int tij;
+               double xd, yd, rij;
+               xd = tsp->node_x_coord[i] - tsp->node_x_coord[j];
+               yd = tsp->node_y_coord[i] - tsp->node_y_coord[j];
+               rij = sqrt((xd * xd + yd * yd) / 10.0);
+               tij = nint(rij);
+               if (tij < rij) dij = tij + 1; else dij = tij;
+            }
+            break;
+         default:
+            xassert(tsp->edge_weight_type != tsp->edge_weight_type);
+      }
+      return dij;
+}
+
+/* eof */
Index: deps/glpk/src/glptsp.h
===================================================================
--- deps/glpk/src/glptsp.h	(revision 9)
+++ deps/glpk/src/glptsp.h	(revision 9)
@@ -0,0 +1,104 @@
+/* glptsp.h (TSP format) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao@gnu.org>.
+*
+*  GLPK is free software: you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by
+*  the Free Software Foundation, either version 3 of the License, or
+*  (at your option) any later version.
+*
+*  GLPK is distributed in the hope that it will be useful, but WITHOUT
+*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+*  License for more details.
+*
+*  You should have received a copy of the GNU General Public License
+*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifndef GLPTSP_H
+#define GLPTSP_H
+
+typedef struct TSP TSP;
+
+struct TSP
+{     /* TSP (or related problem) instance in the format described in
+         the report [G.Reinelt, TSPLIB 95] */
+      /*--------------------------------------------------------------*/
+      /* the specification part */
+      char *name;
+      /* identifies the data file */
+      int type;
+      /* specifies the type of data: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_TSP               1  /* symmetric TSP */
+#define TSP_ATSP              2  /* asymmetric TSP */
+#define TSP_TOUR              3  /* collection of tours */
+      char *comment;
+      /* additional comments (usually the name of the contributor or
+         creator of the problem instance is given here) */
+      int dimension;
+      /* for a TSP or ATSP, the dimension is the number of its nodes
+         for a TOUR it is the dimension of the corresponding problem */
+      int edge_weight_type;
+      /* specifies how the edge weights (or distances) are given: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_EXPLICIT          1  /* listed explicitly */
+#define TSP_EUC_2D            2  /* Eucl. distances in 2-D */
+#define TSP_CEIL_2D           3  /* Eucl. distances in 2-D rounded up */
+#define TSP_GEO               4  /* geographical distances */
+#define TSP_ATT               5  /* special distance function */
+      int edge_weight_format;
+      /* describes the format of the edge weights if they are given
+         explicitly: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_FUNCTION          1  /* given by a function */
+#define TSP_FULL_MATRIX       2  /* given by a full matrix */
+#define TSP_UPPER_ROW         3  /* upper triangulat matrix (row-wise
+                                    without diagonal entries) */
+#define TSP_LOWER_DIAG_ROW    4  /* lower triangular matrix (row-wise
+                                    including diagonal entries) */
+      int display_data_type;
+      /* specifies how a graphical display of the nodes can be
+         obtained: */
+#define TSP_UNDEF             0  /* undefined */
+#define TSP_COORD_DISPLAY     1  /* display is generated from the node
+                                    coordinates */
+#define TSP_TWOD_DISPLAY      2  /* explicit coordinates in 2-D are
+                                    given */
+      /*--------------------------------------------------------------*/
+      /* data part */
+      /* NODE_COORD_SECTION: */
+      double *node_x_coord; /* double node_x_coord[1+dimension]; */
+      double *node_y_coord; /* double node_y_coord[1+dimension]; */
+      /* DISPLAY_DATA_SECTION: */
+      double *dply_x_coord; /* double dply_x_coord[1+dimension]; */
+      double *dply_y_coord; /* double dply_y_coord[1+dimension]; */
+      /* TOUR_SECTION: */
+      int *tour; /* int tour[1+dimension]; */
+      /* EDGE_WEIGHT_SECTION: */
+      int *edge_weight; /* int edge_weight[1+dimension*dimension]; */
+};
+
+#define tsp_read_data         _glp_tsp_read_data
+#define tsp_free_data         _glp_tsp_free_data
+#define tsp_distance          _glp_tsp_distance
+
+TSP *tsp_read_data(char *fname);
+/* read TSP instance data */
+
+void tsp_free_data(TSP *tsp);
+/* free TSP instance data */
+
+int tsp_distance(TSP *tsp, int i, int j);
+/* compute distance between two nodes */
+
+#endif
+
+/* eof */
Index: deps/glpk/src/minisat/LICENSE
===================================================================
--- deps/glpk/src/minisat/LICENSE	(revision 9)
+++ deps/glpk/src/minisat/LICENSE	(revision 9)
@@ -0,0 +1,20 @@
+MiniSat -- Copyright (c) 2005, Niklas Sorensson
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: deps/glpk/src/minisat/README
===================================================================
--- deps/glpk/src/minisat/README	(revision 9)
+++ deps/glpk/src/minisat/README	(revision 9)
@@ -0,0 +1,22 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+      are used with GLPK.
+
+      The original code was modified according to GLPK requirements by
+      Andrew Makhorin <mao@gnu.org>.
+************************************************************************
+MiniSat-C v1.14.1
+========================================
+
+* Fixed some serious bugs.
+* Tweaked to be Visual Studio friendly (by Alan Mishchenko).
+  This disabled reading of gzipped DIMACS files and signal handling,
+  but none of these features are essential (and easy to re-enable, if
+  wanted).
+
+MiniSat-C v1.14
+========================================
+
+Ok, we get it. You hate C++. You hate templates. We agree; C++ is a
+seriously messed up language. Although we are more pragmatic about the
+quirks and maldesigns in C++, we sympathize with you. So here is a
+pure C version of MiniSat, put together by Niklas Sorensson.
Index: deps/glpk/src/minisat/minisat.c
===================================================================
--- deps/glpk/src/minisat/minisat.c	(revision 9)
+++ deps/glpk/src/minisat/minisat.c	(revision 9)
@@ -0,0 +1,1299 @@
+/* minisat.c */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, August 2011 */
+
+/***********************************************************************
+*  MiniSat -- Copyright (c) 2005, Niklas Sorensson
+*  http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+*
+*  Permission is hereby granted, free of charge, to any person
+*  obtaining a copy of this software and associated documentation files
+*  (the "Software"), to deal in the Software without restriction,
+*  including without limitation the rights to use, copy, modify, merge,
+*  publish, distribute, sublicense, and/or sell copies of the Software,
+*  and to permit persons to whom the Software is furnished to do so,
+*  subject to the following conditions:
+*
+*  The above copyright notice and this permission notice shall be
+*  included in all copies or substantial portions of the Software.
+*
+*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+*  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+*  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+*  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+*  SOFTWARE.
+***********************************************************************/
+/* Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko */
+
+#include "glpenv.h"
+#include "minisat.h"
+
+#if 1 /* by mao */
+static void *ymalloc(int size)
+{     void *ptr;
+      xassert(size > 0);
+      ptr = malloc(size);
+      if (ptr == NULL)
+         xerror("MiniSat: no memory available\n");
+      return ptr;
+}
+
+static void *yrealloc(void *ptr, int size)
+{     xassert(size > 0);
+      if (ptr == NULL)
+         ptr = malloc(size);
+      else
+         ptr = realloc(ptr, size);
+      if (ptr == NULL)
+         xerror("MiniSat: no memory available\n");
+      return ptr;
+}
+
+static void yfree(void *ptr)
+{     xassert(ptr != NULL);
+      free(ptr);
+      return;
+}
+
+#define assert  xassert
+#define printf  xprintf
+#define fflush(f) /* nop */
+#define malloc  ymalloc
+#define realloc yrealloc
+#define free    yfree
+#define inline  /* empty */
+#endif
+
+/*====================================================================*/
+/* Debug: */
+
+#if 0
+#define VERBOSEDEBUG 1
+#endif
+
+/* For derivation output (verbosity level 2) */
+#define L_IND    "%-*d"
+#define L_ind    solver_dlevel(s)*3+3,solver_dlevel(s)
+#define L_LIT    "%sx%d"
+#define L_lit(p) lit_sign(p)?"~":"", (lit_var(p))
+
+#if 0 /* by mao */
+/* Just like 'assert()' but expression will be evaluated in the release
+   version as well. */
+static inline void check(int expr) { assert(expr); }
+#endif
+
+#if 0 /* by mao */
+static void printlits(lit* begin, lit* end)
+{
+    int i;
+    for (i = 0; i < end - begin; i++)
+        printf(L_LIT" ",L_lit(begin[i]));
+}
+#endif
+
+/*====================================================================*/
+/* Random numbers: */
+
+/* Returns a random float 0 <= x < 1. Seed must never be 0. */
+static inline double drand(double* seed) {
+    int q;
+    *seed *= 1389796;
+    q = (int)(*seed / 2147483647);
+    *seed -= (double)q * 2147483647;
+    return *seed / 2147483647; }
+
+/* Returns a random integer 0 <= x < size. Seed must never be 0. */
+static inline int irand(double* seed, int size) {
+    return (int)(drand(seed) * size); }
+
+/*====================================================================*/
+/* Predeclarations: */
+
+static void sort(void** array, int size,
+    int(*comp)(const void *, const void *));
+
+/*====================================================================*/
+/* Clause datatype + minor functions: */
+
+#if 0 /* by mao; see minisat.h */
+struct clause_t
+{
+    int size_learnt;
+    lit lits[0];
+};
+#endif
+
+#define clause_size(c) ((c)->size_learnt >> 1)
+
+#define clause_begin(c) ((c)->lits)
+
+#define clause_learnt(c) ((c)->size_learnt & 1)
+
+#define clause_activity(c) \
+    (*((float*)&(c)->lits[(c)->size_learnt>>1]))
+
+#define clause_setactivity(c, a) \
+    (void)(*((float*)&(c)->lits[(c)->size_learnt>>1]) = (a))
+
+/*====================================================================*/
+/* Encode literals in clause pointers: */
+
+#define clause_from_lit(l) \
+      (clause*)((unsigned long)(l) + (unsigned long)(l) + 1)
+
+#define clause_is_lit(c) \
+      ((unsigned long)(c) & 1)
+
+#define clause_read_lit(c) \
+      (lit)((unsigned long)(c) >> 1)
+
+/*====================================================================*/
+/* Simple helpers: */
+
+#define solver_dlevel(s) \
+    (int)veci_size(&(s)->trail_lim)
+
+#define solver_read_wlist(s, l) \
+    (vecp *)(&(s)->wlists[l])
+
+static inline void    vecp_remove(vecp* v, void* e)
+{
+    void** ws = vecp_begin(v);
+    int    j  = 0;
+
+    for (; ws[j] != e  ; j++);
+    assert(j < vecp_size(v));
+    for (; j < vecp_size(v)-1; j++) ws[j] = ws[j+1];
+    vecp_resize(v,vecp_size(v)-1);
+}
+
+/*====================================================================*/
+/* Variable order functions: */
+
+static inline void order_update(solver* s, int v)
+{   /* updateorder */
+    int*    orderpos = s->orderpos;
+    double* activity = s->activity;
+    int*    heap     = veci_begin(&s->order);
+    int     i        = orderpos[v];
+    int     x        = heap[i];
+    int     parent   = (i - 1) / 2;
+
+    assert(s->orderpos[v] != -1);
+
+    while (i != 0 && activity[x] > activity[heap[parent]]){
+        heap[i]           = heap[parent];
+        orderpos[heap[i]] = i;
+        i                 = parent;
+        parent            = (i - 1) / 2;
+    }
+    heap[i]     = x;
+    orderpos[x] = i;
+}
+
+#define order_assigned(s, v) /* nop */
+
+static inline void order_unassigned(solver* s, int v)
+{   /* undoorder */
+    int* orderpos = s->orderpos;
+    if (orderpos[v] == -1){
+        orderpos[v] = veci_size(&s->order);
+        veci_push(&s->order,v);
+        order_update(s,v);
+    }
+}
+
+static int order_select(solver* s, float random_var_freq)
+{   /* selectvar */
+    int*    heap;
+    double* activity;
+    int*    orderpos;
+
+    lbool* values = s->assigns;
+
+    /* Random decision: */
+    if (drand(&s->random_seed) < random_var_freq){
+        int next = irand(&s->random_seed,s->size);
+        assert(next >= 0 && next < s->size);
+        if (values[next] == l_Undef)
+            return next;
+    }
+
+    /* Activity based decision: */
+
+    heap     = veci_begin(&s->order);
+    activity = s->activity;
+    orderpos = s->orderpos;
+
+    while (veci_size(&s->order) > 0){
+        int    next  = heap[0];
+        int    size  = veci_size(&s->order)-1;
+        int    x     = heap[size];
+
+        veci_resize(&s->order,size);
+
+        orderpos[next] = -1;
+
+        if (size > 0){
+            double act   = activity[x];
+
+            int    i     = 0;
+            int    child = 1;
+
+            while (child < size){
+                if (child+1 < size
+                    && activity[heap[child]] < activity[heap[child+1]])
+                    child++;
+
+                assert(child < size);
+
+                if (act >= activity[heap[child]])
+                    break;
+
+                heap[i]           = heap[child];
+                orderpos[heap[i]] = i;
+                i                 = child;
+                child             = 2 * child + 1;
+            }
+            heap[i]           = x;
+            orderpos[heap[i]] = i;
+        }
+
+        if (values[next] == l_Undef)
+            return next;
+    }
+
+    return var_Undef;
+}
+
+/*====================================================================*/
+/* Activity functions: */
+
+static inline void act_var_rescale(solver* s) {
+    double* activity = s->activity;
+    int i;
+    for (i = 0; i < s->size; i++)
+        activity[i] *= 1e-100;
+    s->var_inc *= 1e-100;
+}
+
+static inline void act_var_bump(solver* s, int v) {
+    double* activity = s->activity;
+    if ((activity[v] += s->var_inc) > 1e100)
+        act_var_rescale(s);
+
+    /* printf("bump %d %f\n", v-1, activity[v]); */
+
+    if (s->orderpos[v] != -1)
+        order_update(s,v);
+
+}
+
+static inline void act_var_decay(solver* s)
+    { s->var_inc *= s->var_decay; }
+
+static inline void act_clause_rescale(solver* s) {
+    clause** cs = (clause**)vecp_begin(&s->learnts);
+    int i;
+    for (i = 0; i < vecp_size(&s->learnts); i++){
+        float a = clause_activity(cs[i]);
+        clause_setactivity(cs[i], a * (float)1e-20);
+    }
+    s->cla_inc *= (float)1e-20;
+}
+
+static inline void act_clause_bump(solver* s, clause *c) {
+    float a = clause_activity(c) + s->cla_inc;
+    clause_setactivity(c,a);
+    if (a > 1e20) act_clause_rescale(s);
+}
+
+static inline void act_clause_decay(solver* s)
+    { s->cla_inc *= s->cla_decay; }
+
+/*====================================================================*/
+/* Clause functions: */
+
+/* pre: size > 1 && no variable occurs twice
+ */
+static clause* clause_new(solver* s, lit* begin, lit* end, int learnt)
+{
+    int size;
+    clause* c;
+    int i;
+
+    assert(end - begin > 1);
+    assert(learnt >= 0 && learnt < 2);
+    size           = end - begin;
+    c              = (clause*)malloc(sizeof(clause)
+                     + sizeof(lit) * size + learnt * sizeof(float));
+    c->size_learnt = (size << 1) | learnt;
+#if 0 /* by mao; meaningless non-portable check */
+    assert(((unsigned int)c & 1) == 0);
+#endif
+
+    for (i = 0; i < size; i++)
+        c->lits[i] = begin[i];
+
+    if (learnt)
+        *((float*)&c->lits[size]) = 0.0;
+
+    assert(begin[0] >= 0);
+    assert(begin[0] < s->size*2);
+    assert(begin[1] >= 0);
+    assert(begin[1] < s->size*2);
+
+    assert(lit_neg(begin[0]) < s->size*2);
+    assert(lit_neg(begin[1]) < s->size*2);
+
+    /* vecp_push(solver_read_wlist(s,lit_neg(begin[0])),(void*)c); */
+    /* vecp_push(solver_read_wlist(s,lit_neg(begin[1])),(void*)c); */
+
+    vecp_push(solver_read_wlist(s,lit_neg(begin[0])),
+        (void*)(size > 2 ? c : clause_from_lit(begin[1])));
+    vecp_push(solver_read_wlist(s,lit_neg(begin[1])),
+        (void*)(size > 2 ? c : clause_from_lit(begin[0])));
+
+    return c;
+}
+
+static void clause_remove(solver* s, clause* c)
+{
+    lit* lits = clause_begin(c);
+    assert(lit_neg(lits[0]) < s->size*2);
+    assert(lit_neg(lits[1]) < s->size*2);
+
+    /* vecp_remove(solver_read_wlist(s,lit_neg(lits[0])),(void*)c); */
+    /* vecp_remove(solver_read_wlist(s,lit_neg(lits[1])),(void*)c); */
+
+    assert(lits[0] < s->size*2);
+    vecp_remove(solver_read_wlist(s,lit_neg(lits[0])),
+        (void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[1])));
+    vecp_remove(solver_read_wlist(s,lit_neg(lits[1])),
+        (void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[0])));
+
+    if (clause_learnt(c)){
+        s->stats.learnts--;
+        s->stats.learnts_literals -= clause_size(c);
+    }else{
+        s->stats.clauses--;
+        s->stats.clauses_literals -= clause_size(c);
+    }
+
+    free(c);
+}
+
+static lbool clause_simplify(solver* s, clause* c)
+{
+    lit*   lits   = clause_begin(c);
+    lbool* values = s->assigns;
+    int i;
+
+    assert(solver_dlevel(s) == 0);
+
+    for (i = 0; i < clause_size(c); i++){
+        lbool sig = !lit_sign(lits[i]); sig += sig - 1;
+        if (values[lit_var(lits[i])] == sig)
+            return l_True;
+    }
+    return l_False;
+}
+
+/*====================================================================*/
+/* Minor (solver) functions: */
+
+void solver_setnvars(solver* s,int n)
+{
+    int var;
+
+    if (s->cap < n){
+
+        while (s->cap < n) s->cap = s->cap*2+1;
+
+        s->wlists    = (vecp*)   realloc(s->wlists,
+                                 sizeof(vecp)*s->cap*2);
+        s->activity  = (double*) realloc(s->activity,
+                                 sizeof(double)*s->cap);
+        s->assigns   = (lbool*)  realloc(s->assigns,
+                                 sizeof(lbool)*s->cap);
+        s->orderpos  = (int*)    realloc(s->orderpos,
+                                 sizeof(int)*s->cap);
+        s->reasons   = (clause**)realloc(s->reasons,
+                                 sizeof(clause*)*s->cap);
+        s->levels    = (int*)    realloc(s->levels,
+                                 sizeof(int)*s->cap);
+        s->tags      = (lbool*)  realloc(s->tags,
+                                 sizeof(lbool)*s->cap);
+        s->trail     = (lit*)    realloc(s->trail,
+                                 sizeof(lit)*s->cap);
+    }
+
+    for (var = s->size; var < n; var++){
+        vecp_new(&s->wlists[2*var]);
+        vecp_new(&s->wlists[2*var+1]);
+        s->activity [var] = 0;
+        s->assigns  [var] = l_Undef;
+        s->orderpos [var] = veci_size(&s->order);
+        s->reasons  [var] = (clause*)0;
+        s->levels   [var] = 0;
+        s->tags     [var] = l_Undef;
+
+        /* does not hold because variables enqueued at top level will
+           not be reinserted in the heap
+           assert(veci_size(&s->order) == var);
+         */
+        veci_push(&s->order,var);
+        order_update(s, var);
+    }
+
+    s->size = n > s->size ? n : s->size;
+}
+
+static inline bool enqueue(solver* s, lit l, clause* from)
+{
+    lbool* values = s->assigns;
+    int    v      = lit_var(l);
+    lbool  val    = values[v];
+    lbool  sig;
+#ifdef VERBOSEDEBUG
+    printf(L_IND"enqueue("L_LIT")\n", L_ind, L_lit(l));
+#endif
+
+    /* lbool */ sig = !lit_sign(l); sig += sig - 1;
+    if (val != l_Undef){
+        return val == sig;
+    }else{
+        /* New fact -- store it. */
+        int*     levels;
+        clause** reasons;
+#ifdef VERBOSEDEBUG
+        printf(L_IND"bind("L_LIT")\n", L_ind, L_lit(l));
+#endif
+        /* int*     */ levels  = s->levels;
+        /* clause** */ reasons = s->reasons;
+
+        values [v] = sig;
+        levels [v] = solver_dlevel(s);
+        reasons[v] = from;
+        s->trail[s->qtail++] = l;
+
+        order_assigned(s, v);
+        return true;
+    }
+}
+
+static inline void assume(solver* s, lit l){
+    assert(s->qtail == s->qhead);
+    assert(s->assigns[lit_var(l)] == l_Undef);
+#ifdef VERBOSEDEBUG
+    printf(L_IND"assume("L_LIT")\n", L_ind, L_lit(l));
+#endif
+    veci_push(&s->trail_lim,s->qtail);
+    enqueue(s,l,(clause*)0);
+}
+
+static inline void solver_canceluntil(solver* s, int level) {
+    lit*     trail;
+    lbool*   values;
+    clause** reasons;
+    int      bound;
+    int      c;
+
+    if (solver_dlevel(s) <= level)
+        return;
+
+    trail   = s->trail;
+    values  = s->assigns;
+    reasons = s->reasons;
+    bound   = (veci_begin(&s->trail_lim))[level];
+
+    for (c = s->qtail-1; c >= bound; c--) {
+        int     x  = lit_var(trail[c]);
+        values [x] = l_Undef;
+        reasons[x] = (clause*)0;
+    }
+
+    for (c = s->qhead-1; c >= bound; c--)
+        order_unassigned(s,lit_var(trail[c]));
+
+    s->qhead = s->qtail = bound;
+    veci_resize(&s->trail_lim,level);
+}
+
+static void solver_record(solver* s, veci* cls)
+{
+    lit*    begin = veci_begin(cls);
+    lit*    end   = begin + veci_size(cls);
+    clause* c     = (veci_size(cls) > 1) ? clause_new(s,begin,end,1)
+                                         : (clause*)0;
+    enqueue(s,*begin,c);
+
+    assert(veci_size(cls) > 0);
+
+    if (c != 0) {
+        vecp_push(&s->learnts,c);
+        act_clause_bump(s,c);
+        s->stats.learnts++;
+        s->stats.learnts_literals += veci_size(cls);
+    }
+}
+
+static double solver_progress(solver* s)
+{
+    lbool*  values = s->assigns;
+    int*    levels = s->levels;
+    int     i;
+
+    double  progress = 0;
+    double  F        = 1.0 / s->size;
+    for (i = 0; i < s->size; i++)
+        if (values[i] != l_Undef)
+            progress += pow(F, levels[i]);
+    return progress / s->size;
+}
+
+/*====================================================================*/
+/* Major methods: */
+
+static bool solver_lit_removable(solver* s, lit l, int minl)
+{
+    lbool*   tags    = s->tags;
+    clause** reasons = s->reasons;
+    int*     levels  = s->levels;
+    int      top     = veci_size(&s->tagged);
+
+    assert(lit_var(l) >= 0 && lit_var(l) < s->size);
+    assert(reasons[lit_var(l)] != 0);
+    veci_resize(&s->stack,0);
+    veci_push(&s->stack,lit_var(l));
+
+    while (veci_size(&s->stack) > 0){
+        clause* c;
+        int v = veci_begin(&s->stack)[veci_size(&s->stack)-1];
+        assert(v >= 0 && v < s->size);
+        veci_resize(&s->stack,veci_size(&s->stack)-1);
+        assert(reasons[v] != 0);
+        c    = reasons[v];
+
+        if (clause_is_lit(c)){
+            int v = lit_var(clause_read_lit(c));
+            if (tags[v] == l_Undef && levels[v] != 0){
+                if (reasons[v] != 0
+                    && ((1 << (levels[v] & 31)) & minl)){
+                    veci_push(&s->stack,v);
+                    tags[v] = l_True;
+                    veci_push(&s->tagged,v);
+                }else{
+                    int* tagged = veci_begin(&s->tagged);
+                    int j;
+                    for (j = top; j < veci_size(&s->tagged); j++)
+                        tags[tagged[j]] = l_Undef;
+                    veci_resize(&s->tagged,top);
+                    return false;
+                }
+            }
+        }else{
+            lit*    lits = clause_begin(c);
+            int     i, j;
+
+            for (i = 1; i < clause_size(c); i++){
+                int v = lit_var(lits[i]);
+                if (tags[v] == l_Undef && levels[v] != 0){
+                    if (reasons[v] != 0
+                        && ((1 << (levels[v] & 31)) & minl)){
+
+                        veci_push(&s->stack,lit_var(lits[i]));
+                        tags[v] = l_True;
+                        veci_push(&s->tagged,v);
+                    }else{
+                        int* tagged = veci_begin(&s->tagged);
+                        for (j = top; j < veci_size(&s->tagged); j++)
+                            tags[tagged[j]] = l_Undef;
+                        veci_resize(&s->tagged,top);
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+static void solver_analyze(solver* s, clause* c, veci* learnt)
+{
+    lit*     trail   = s->trail;
+    lbool*   tags    = s->tags;
+    clause** reasons = s->reasons;
+    int*     levels  = s->levels;
+    int      cnt     = 0;
+    lit      p       = lit_Undef;
+    int      ind     = s->qtail-1;
+    lit*     lits;
+    int      i, j, minl;
+    int*     tagged;
+
+    veci_push(learnt,lit_Undef);
+
+    do{
+        assert(c != 0);
+
+        if (clause_is_lit(c)){
+            lit q = clause_read_lit(c);
+            assert(lit_var(q) >= 0 && lit_var(q) < s->size);
+            if (tags[lit_var(q)] == l_Undef && levels[lit_var(q)] > 0){
+                tags[lit_var(q)] = l_True;
+                veci_push(&s->tagged,lit_var(q));
+                act_var_bump(s,lit_var(q));
+                if (levels[lit_var(q)] == solver_dlevel(s))
+                    cnt++;
+                else
+                    veci_push(learnt,q);
+            }
+        }else{
+
+            if (clause_learnt(c))
+                act_clause_bump(s,c);
+
+            lits = clause_begin(c);
+            /* printlits(lits,lits+clause_size(c)); printf("\n"); */
+            for (j = (p == lit_Undef ? 0 : 1); j < clause_size(c); j++){
+                lit q = lits[j];
+                assert(lit_var(q) >= 0 && lit_var(q) < s->size);
+                if (tags[lit_var(q)] == l_Undef
+                    && levels[lit_var(q)] > 0){
+                    tags[lit_var(q)] = l_True;
+                    veci_push(&s->tagged,lit_var(q));
+                    act_var_bump(s,lit_var(q));
+                    if (levels[lit_var(q)] == solver_dlevel(s))
+                        cnt++;
+                    else
+                        veci_push(learnt,q);
+                }
+            }
+        }
+
+        while (tags[lit_var(trail[ind--])] == l_Undef);
+
+        p = trail[ind+1];
+        c = reasons[lit_var(p)];
+        cnt--;
+
+    }while (cnt > 0);
+
+    *veci_begin(learnt) = lit_neg(p);
+
+    lits = veci_begin(learnt);
+    minl = 0;
+    for (i = 1; i < veci_size(learnt); i++){
+        int lev = levels[lit_var(lits[i])];
+        minl    |= 1 << (lev & 31);
+    }
+
+    /* simplify (full) */
+    for (i = j = 1; i < veci_size(learnt); i++){
+        if (reasons[lit_var(lits[i])] == 0
+            || !solver_lit_removable(s,lits[i],minl))
+            lits[j++] = lits[i];
+    }
+
+    /* update size of learnt + statistics */
+    s->stats.max_literals += veci_size(learnt);
+    veci_resize(learnt,j);
+    s->stats.tot_literals += j;
+
+    /* clear tags */
+    tagged = veci_begin(&s->tagged);
+    for (i = 0; i < veci_size(&s->tagged); i++)
+        tags[tagged[i]] = l_Undef;
+    veci_resize(&s->tagged,0);
+
+#ifdef DEBUG
+    for (i = 0; i < s->size; i++)
+        assert(tags[i] == l_Undef);
+#endif
+
+#ifdef VERBOSEDEBUG
+    printf(L_IND"Learnt {", L_ind);
+    for (i = 0; i < veci_size(learnt); i++)
+        printf(" "L_LIT, L_lit(lits[i]));
+#endif
+    if (veci_size(learnt) > 1){
+        int max_i = 1;
+        int max   = levels[lit_var(lits[1])];
+        lit tmp;
+
+        for (i = 2; i < veci_size(learnt); i++)
+            if (levels[lit_var(lits[i])] > max){
+                max   = levels[lit_var(lits[i])];
+                max_i = i;
+            }
+
+        tmp         = lits[1];
+        lits[1]     = lits[max_i];
+        lits[max_i] = tmp;
+    }
+#ifdef VERBOSEDEBUG
+    {
+        int lev = veci_size(learnt) > 1 ? levels[lit_var(lits[1])] : 0;
+        printf(" } at level %d\n", lev);
+    }
+#endif
+}
+
+clause* solver_propagate(solver* s)
+{
+    lbool*  values = s->assigns;
+    clause* confl  = (clause*)0;
+    lit*    lits;
+
+    /* printf("solver_propagate\n"); */
+    while (confl == 0 && s->qtail - s->qhead > 0){
+        lit  p  = s->trail[s->qhead++];
+        vecp* ws = solver_read_wlist(s,p);
+        clause **begin = (clause**)vecp_begin(ws);
+        clause **end   = begin + vecp_size(ws);
+        clause **i, **j;
+
+        s->stats.propagations++;
+        s->simpdb_props--;
+
+        /* printf("checking lit %d: "L_LIT"\n", veci_size(ws),
+               L_lit(p)); */
+        for (i = j = begin; i < end; ){
+            if (clause_is_lit(*i)){
+                *j++ = *i;
+                if (!enqueue(s,clause_read_lit(*i),clause_from_lit(p))){
+                    confl = s->binary;
+                    (clause_begin(confl))[1] = lit_neg(p);
+                    (clause_begin(confl))[0] = clause_read_lit(*i++);
+
+                    /* Copy the remaining watches: */
+                    while (i < end)
+                        *j++ = *i++;
+                }
+            }else{
+                lit false_lit;
+                lbool sig;
+
+                lits = clause_begin(*i);
+
+                /* Make sure the false literal is data[1]: */
+                false_lit = lit_neg(p);
+                if (lits[0] == false_lit){
+                    lits[0] = lits[1];
+                    lits[1] = false_lit;
+                }
+                assert(lits[1] == false_lit);
+                /* printf("checking clause: ");
+                   printlits(lits, lits+clause_size(*i));
+                   printf("\n"); */
+
+                /* If 0th watch is true, then clause is already
+                   satisfied. */
+                sig = !lit_sign(lits[0]); sig += sig - 1;
+                if (values[lit_var(lits[0])] == sig){
+                    *j++ = *i;
+                }else{
+                    /* Look for new watch: */
+                    lit* stop = lits + clause_size(*i);
+                    lit* k;
+                    for (k = lits + 2; k < stop; k++){
+                        lbool sig = lit_sign(*k); sig += sig - 1;
+                        if (values[lit_var(*k)] != sig){
+                            lits[1] = *k;
+                            *k = false_lit;
+                            vecp_push(solver_read_wlist(s,
+                                lit_neg(lits[1])),*i);
+                            goto next; }
+                    }
+
+                    *j++ = *i;
+                    /* Clause is unit under assignment: */
+                    if (!enqueue(s,lits[0], *i)){
+                        confl = *i++;
+                        /* Copy the remaining watches: */
+                        while (i < end)
+                            *j++ = *i++;
+                    }
+                }
+            }
+        next:
+            i++;
+        }
+
+        s->stats.inspects += j - (clause**)vecp_begin(ws);
+        vecp_resize(ws,j - (clause**)vecp_begin(ws));
+    }
+
+    return confl;
+}
+
+static inline int clause_cmp (const void* x, const void* y) {
+    return clause_size((clause*)x) > 2
+           && (clause_size((clause*)y) == 2
+               || clause_activity((clause*)x)
+                  < clause_activity((clause*)y)) ? -1 : 1; }
+
+void solver_reducedb(solver* s)
+{
+    int      i, j;
+    double   extra_lim = s->cla_inc / vecp_size(&s->learnts);
+             /* Remove any clause below this activity */
+    clause** learnts = (clause**)vecp_begin(&s->learnts);
+    clause** reasons = s->reasons;
+
+    sort(vecp_begin(&s->learnts), vecp_size(&s->learnts), clause_cmp);
+
+    for (i = j = 0; i < vecp_size(&s->learnts) / 2; i++){
+        if (clause_size(learnts[i]) > 2
+            && reasons[lit_var(*clause_begin(learnts[i]))]
+               != learnts[i])
+            clause_remove(s,learnts[i]);
+        else
+            learnts[j++] = learnts[i];
+    }
+    for (; i < vecp_size(&s->learnts); i++){
+        if (clause_size(learnts[i]) > 2
+            && reasons[lit_var(*clause_begin(learnts[i]))]
+               != learnts[i]
+            && clause_activity(learnts[i]) < extra_lim)
+            clause_remove(s,learnts[i]);
+        else
+            learnts[j++] = learnts[i];
+    }
+
+    /* printf("reducedb deleted %d\n", vecp_size(&s->learnts) - j); */
+
+    vecp_resize(&s->learnts,j);
+}
+
+static lbool solver_search(solver* s, int nof_conflicts,
+                           int nof_learnts)
+{
+    int*    levels          = s->levels;
+    double  var_decay       = 0.95;
+    double  clause_decay    = 0.999;
+    double  random_var_freq = 0.02;
+
+    int     conflictC       = 0;
+    veci    learnt_clause;
+
+    assert(s->root_level == solver_dlevel(s));
+
+    s->stats.starts++;
+    s->var_decay = (float)(1 / var_decay   );
+    s->cla_decay = (float)(1 / clause_decay);
+    veci_resize(&s->model,0);
+    veci_new(&learnt_clause);
+
+    for (;;){
+        clause* confl = solver_propagate(s);
+        if (confl != 0){
+            /* CONFLICT */
+            int blevel;
+
+#ifdef VERBOSEDEBUG
+            printf(L_IND"**CONFLICT**\n", L_ind);
+#endif
+            s->stats.conflicts++; conflictC++;
+            if (solver_dlevel(s) == s->root_level){
+                veci_delete(&learnt_clause);
+                return l_False;
+            }
+
+            veci_resize(&learnt_clause,0);
+            solver_analyze(s, confl, &learnt_clause);
+            blevel = veci_size(&learnt_clause) > 1
+                     ? levels[lit_var(veci_begin(&learnt_clause)[1])]
+                     : s->root_level;
+            blevel = s->root_level > blevel ? s->root_level : blevel;
+            solver_canceluntil(s,blevel);
+            solver_record(s,&learnt_clause);
+            act_var_decay(s);
+            act_clause_decay(s);
+
+        }else{
+            /* NO CONFLICT */
+            int next;
+
+            if (nof_conflicts >= 0 && conflictC >= nof_conflicts){
+                /* Reached bound on number of conflicts: */
+                s->progress_estimate = solver_progress(s);
+                solver_canceluntil(s,s->root_level);
+                veci_delete(&learnt_clause);
+                return l_Undef; }
+
+            if (solver_dlevel(s) == 0)
+                /* Simplify the set of problem clauses: */
+                solver_simplify(s);
+
+            if (nof_learnts >= 0
+                && vecp_size(&s->learnts) - s->qtail >= nof_learnts)
+                /* Reduce the set of learnt clauses: */
+                solver_reducedb(s);
+
+            /* New variable decision: */
+            s->stats.decisions++;
+            next = order_select(s,(float)random_var_freq);
+
+            if (next == var_Undef){
+                /* Model found: */
+                lbool* values = s->assigns;
+                int i;
+                for (i = 0; i < s->size; i++)
+                    veci_push(&s->model,(int)values[i]);
+                solver_canceluntil(s,s->root_level);
+                veci_delete(&learnt_clause);
+
+                /*
+                veci apa; veci_new(&apa);
+                for (i = 0; i < s->size; i++)
+                    veci_push(&apa,(int)(s->model.ptr[i] == l_True
+                        ? toLit(i) : lit_neg(toLit(i))));
+                printf("model: ");
+                printlits((lit*)apa.ptr,
+                    (lit*)apa.ptr + veci_size(&apa)); printf("\n");
+                veci_delete(&apa);
+                */
+
+                return l_True;
+            }
+
+            assume(s,lit_neg(toLit(next)));
+        }
+    }
+
+#if 0 /* by mao; unreachable code */
+    return l_Undef; /* cannot happen */
+#endif
+}
+
+/*====================================================================*/
+/* External solver functions: */
+
+solver* solver_new(void)
+{
+    solver* s = (solver*)malloc(sizeof(solver));
+
+    /* initialize vectors */
+    vecp_new(&s->clauses);
+    vecp_new(&s->learnts);
+    veci_new(&s->order);
+    veci_new(&s->trail_lim);
+    veci_new(&s->tagged);
+    veci_new(&s->stack);
+    veci_new(&s->model);
+
+    /* initialize arrays */
+    s->wlists    = 0;
+    s->activity  = 0;
+    s->assigns   = 0;
+    s->orderpos  = 0;
+    s->reasons   = 0;
+    s->levels    = 0;
+    s->tags      = 0;
+    s->trail     = 0;
+
+    /* initialize other vars */
+    s->size                   = 0;
+    s->cap                    = 0;
+    s->qhead                  = 0;
+    s->qtail                  = 0;
+    s->cla_inc                = 1;
+    s->cla_decay              = 1;
+    s->var_inc                = 1;
+    s->var_decay              = 1;
+    s->root_level             = 0;
+    s->simpdb_assigns         = 0;
+    s->simpdb_props           = 0;
+    s->random_seed            = 91648253;
+    s->progress_estimate      = 0;
+    s->binary                 = (clause*)malloc(sizeof(clause)
+                                                + sizeof(lit)*2);
+    s->binary->size_learnt    = (2 << 1);
+    s->verbosity              = 0;
+
+    s->stats.starts           = 0;
+    s->stats.decisions        = 0;
+    s->stats.propagations     = 0;
+    s->stats.inspects         = 0;
+    s->stats.conflicts        = 0;
+    s->stats.clauses          = 0;
+    s->stats.clauses_literals = 0;
+    s->stats.learnts          = 0;
+    s->stats.learnts_literals = 0;
+    s->stats.max_literals     = 0;
+    s->stats.tot_literals     = 0;
+
+    return s;
+}
+
+void solver_delete(solver* s)
+{
+    int i;
+    for (i = 0; i < vecp_size(&s->clauses); i++)
+        free(vecp_begin(&s->clauses)[i]);
+
+    for (i = 0; i < vecp_size(&s->learnts); i++)
+        free(vecp_begin(&s->learnts)[i]);
+
+    /* delete vectors */
+    vecp_delete(&s->clauses);
+    vecp_delete(&s->learnts);
+    veci_delete(&s->order);
+    veci_delete(&s->trail_lim);
+    veci_delete(&s->tagged);
+    veci_delete(&s->stack);
+    veci_delete(&s->model);
+    free(s->binary);
+
+    /* delete arrays */
+    if (s->wlists != 0){
+        int i;
+        for (i = 0; i < s->size*2; i++)
+            vecp_delete(&s->wlists[i]);
+
+        /* if one is different from null, all are */
+        free(s->wlists);
+        free(s->activity );
+        free(s->assigns  );
+        free(s->orderpos );
+        free(s->reasons  );
+        free(s->levels   );
+        free(s->trail    );
+        free(s->tags     );
+    }
+
+    free(s);
+}
+
+bool solver_addclause(solver* s, lit* begin, lit* end)
+{
+    lit *i,*j;
+    int maxvar;
+    lbool* values;
+    lit last;
+
+    if (begin == end) return false;
+
+    /* printlits(begin,end); printf("\n"); */
+    /* insertion sort */
+    maxvar = lit_var(*begin);
+    for (i = begin + 1; i < end; i++){
+        lit l = *i;
+        maxvar = lit_var(l) > maxvar ? lit_var(l) : maxvar;
+        for (j = i; j > begin && *(j-1) > l; j--)
+            *j = *(j-1);
+        *j = l;
+    }
+    solver_setnvars(s,maxvar+1);
+
+    /* printlits(begin,end); printf("\n"); */
+    values = s->assigns;
+
+    /* delete duplicates */
+    last = lit_Undef;
+    for (i = j = begin; i < end; i++){
+        /* printf("lit: "L_LIT", value = %d\n", L_lit(*i),
+        (lit_sign(*i) ? -values[lit_var(*i)] : values[lit_var(*i)])); */
+        lbool sig = !lit_sign(*i); sig += sig - 1;
+        if (*i == lit_neg(last) || sig == values[lit_var(*i)])
+            return true;   /* tautology */
+        else if (*i != last && values[lit_var(*i)] == l_Undef)
+            last = *j++ = *i;
+    }
+
+    /* printf("final: "); printlits(begin,j); printf("\n"); */
+
+    if (j == begin)          /* empty clause */
+        return false;
+    else if (j - begin == 1) /* unit clause */
+        return enqueue(s,*begin,(clause*)0);
+
+    /* create new clause */
+    vecp_push(&s->clauses,clause_new(s,begin,j,0));
+
+    s->stats.clauses++;
+    s->stats.clauses_literals += j - begin;
+
+    return true;
+}
+
+bool   solver_simplify(solver* s)
+{
+    clause** reasons;
+    int type;
+
+    assert(solver_dlevel(s) == 0);
+
+    if (solver_propagate(s) != 0)
+        return false;
+
+    if (s->qhead == s->simpdb_assigns || s->simpdb_props > 0)
+        return true;
+
+    reasons = s->reasons;
+    for (type = 0; type < 2; type++){
+        vecp*    cs  = type ? &s->learnts : &s->clauses;
+        clause** cls = (clause**)vecp_begin(cs);
+
+        int i, j;
+        for (j = i = 0; i < vecp_size(cs); i++){
+            if (reasons[lit_var(*clause_begin(cls[i]))] != cls[i] &&
+                clause_simplify(s,cls[i]) == l_True)
+                clause_remove(s,cls[i]);
+            else
+                cls[j++] = cls[i];
+        }
+        vecp_resize(cs,j);
+    }
+
+    s->simpdb_assigns = s->qhead;
+    /* (shouldn't depend on 'stats' really, but it will do for now) */
+    s->simpdb_props   = (int)(s->stats.clauses_literals
+                              + s->stats.learnts_literals);
+
+    return true;
+}
+
+bool   solver_solve(solver* s, lit* begin, lit* end)
+{
+    double  nof_conflicts = 100;
+    double  nof_learnts   = solver_nclauses(s) / 3;
+    lbool   status        = l_Undef;
+    lbool*  values        = s->assigns;
+    lit*    i;
+
+    /* printf("solve: "); printlits(begin, end); printf("\n"); */
+    for (i = begin; i < end; i++){
+        switch (lit_sign(*i) ? -values[lit_var(*i)]
+                             : values[lit_var(*i)]){
+        case 1: /* l_True: */
+            break;
+        case 0: /* l_Undef */
+            assume(s, *i);
+            if (solver_propagate(s) == NULL)
+                break;
+            /* falltrough */
+        case -1: /* l_False */
+            solver_canceluntil(s, 0);
+            return false;
+        }
+    }
+
+    s->root_level = solver_dlevel(s);
+
+    if (s->verbosity >= 1){
+        printf("==================================[MINISAT]============"
+               "=======================\n");
+        printf("| Conflicts |     ORIGINAL     |              LEARNT   "
+               "           | Progress |\n");
+        printf("|           | Clauses Literals |   Limit Clauses Litera"
+               "ls  Lit/Cl |          |\n");
+        printf("======================================================="
+               "=======================\n");
+    }
+
+    while (status == l_Undef){
+        double Ratio = (s->stats.learnts == 0)? 0.0 :
+            s->stats.learnts_literals / (double)s->stats.learnts;
+
+        if (s->verbosity >= 1){
+            printf("| %9.0f | %7.0f %8.0f | %7.0f %7.0f %8.0f %7.1f | %"
+                   "6.3f %% |\n",
+                (double)s->stats.conflicts,
+                (double)s->stats.clauses,
+                (double)s->stats.clauses_literals,
+                (double)nof_learnts,
+                (double)s->stats.learnts,
+                (double)s->stats.learnts_literals,
+                Ratio,
+                s->progress_estimate*100);
+            fflush(stdout);
+        }
+        status = solver_search(s,(int)nof_conflicts, (int)nof_learnts);
+        nof_conflicts *= 1.5;
+        nof_learnts   *= 1.1;
+    }
+    if (s->verbosity >= 1)
+        printf("======================================================="
+               "=======================\n");
+
+    solver_canceluntil(s,0);
+    return status != l_False;
+}
+
+int solver_nvars(solver* s)
+{
+    return s->size;
+}
+
+int solver_nclauses(solver* s)
+{
+    return vecp_size(&s->clauses);
+}
+
+int solver_nconflicts(solver* s)
+{
+    return (int)s->stats.conflicts;
+}
+
+/*====================================================================*/
+/* Sorting functions (sigh): */
+
+static inline void selectionsort(void** array, int size,
+                                 int(*comp)(const void *, const void *))
+{
+    int     i, j, best_i;
+    void*   tmp;
+
+    for (i = 0; i < size-1; i++){
+        best_i = i;
+        for (j = i+1; j < size; j++){
+            if (comp(array[j], array[best_i]) < 0)
+                best_i = j;
+        }
+        tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
+    }
+}
+
+static void sortrnd(void** array, int size,
+                    int(*comp)(const void *, const void *),
+                    double* seed)
+{
+    if (size <= 15)
+        selectionsort(array, size, comp);
+
+    else{
+        void*       pivot = array[irand(seed, size)];
+        void*       tmp;
+        int         i = -1;
+        int         j = size;
+
+        for(;;){
+            do i++; while(comp(array[i], pivot)<0);
+            do j--; while(comp(pivot, array[j])<0);
+
+            if (i >= j) break;
+
+            tmp = array[i]; array[i] = array[j]; array[j] = tmp;
+        }
+
+        sortrnd(array    , i     , comp, seed);
+        sortrnd(&array[i], size-i, comp, seed);
+    }
+}
+
+static void sort(void** array, int size,
+          int(*comp)(const void *, const void *))
+{
+    double seed = 91648253;
+    sortrnd(array,size,comp,&seed);
+}
+
+/* eof */
Index: deps/glpk/src/minisat/minisat.h
===================================================================
--- deps/glpk/src/minisat/minisat.h	(revision 9)
+++ deps/glpk/src/minisat/minisat.h	(revision 9)
@@ -0,0 +1,230 @@
+/* minisat.h */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, August 2011 */
+
+/***********************************************************************
+*  MiniSat -- Copyright (c) 2005, Niklas Sorensson
+*  http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/
+*
+*  Permission is hereby granted, free of charge, to any person
+*  obtaining a copy of this software and associated documentation files
+*  (the "Software"), to deal in the Software without restriction,
+*  including without limitation the rights to use, copy, modify, merge,
+*  publish, distribute, sublicense, and/or sell copies of the Software,
+*  and to permit persons to whom the Software is furnished to do so,
+*  subject to the following conditions:
+*
+*  The above copyright notice and this permission notice shall be
+*  included in all copies or substantial portions of the Software.
+*
+*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+*  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+*  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+*  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+*  SOFTWARE.
+***********************************************************************/
+/* Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko */
+
+#ifndef MINISAT_H
+#define MINISAT_H
+
+/*====================================================================*/
+/* Simple types: */
+
+typedef int bool;
+
+#define true  1
+#define false 0
+
+typedef int  lit;
+#if 0 /* by mao */
+typedef char lbool;
+#else
+typedef int lbool;
+#endif
+
+#define var_Undef (int)(-1)
+#define lit_Undef (lit)(-2)
+
+#define l_Undef (lbool)0
+#define l_True  (lbool)1
+#define l_False (lbool)(-1)
+
+#define toLit(v) (lit)((v) + (v))
+#define lit_neg(l) (lit)((l) ^ 1)
+#define lit_var(l) (int)((l) >> 1)
+#define lit_sign(l) (int)((l) & 1)
+
+/*====================================================================*/
+/* Vectors: */
+
+/* vector of 32-bit intergers (added for 64-bit portability) */
+typedef struct /* veci_t */ {
+    int    size;
+    int    cap;
+    int*   ptr;
+} veci;
+
+#define veci_new(v) \
+{   (v)->size = 0; \
+    (v)->cap  = 4; \
+    (v)->ptr  = (int*)malloc(sizeof(int)*(v)->cap); \
+}
+
+#define veci_delete(v) free((v)->ptr)
+
+#define veci_begin(v) ((v)->ptr)
+
+#define veci_size(v) ((v)->size)
+
+#define veci_resize(v, k) (void)((v)->size = (k))
+/* only safe to shrink !! */
+
+#define veci_push(v, e) \
+{   if ((v)->size == (v)->cap) \
+    {   int newsize = (v)->cap * 2+1; \
+        (v)->ptr = (int*)realloc((v)->ptr,sizeof(int)*newsize); \
+        (v)->cap = newsize; \
+    } \
+    (v)->ptr[(v)->size++] = (e); \
+}
+
+/* vector of 32- or 64-bit pointers */
+typedef struct /* vecp_t */ {
+    int    size;
+    int    cap;
+    void** ptr;
+} vecp;
+
+#define vecp_new(v) \
+{   (v)->size = 0; \
+    (v)->cap  = 4; \
+    (v)->ptr  = (void**)malloc(sizeof(void*)*(v)->cap); \
+}
+
+#define vecp_delete(v) free((v)->ptr)
+
+#define vecp_begin(v) ((v)->ptr)
+
+#define vecp_size(v) ((v)->size)
+
+#define vecp_resize(v, k) (void)((v)->size = (k))
+/* only safe to shrink !! */
+
+#define vecp_push(v, e) \
+{   if ((v)->size == (v)->cap) \
+    {   int newsize = (v)->cap * 2+1; \
+        (v)->ptr = (void**)realloc((v)->ptr,sizeof(void*)*newsize); \
+        (v)->cap = newsize; \
+    } \
+    (v)->ptr[(v)->size++] = (e); \
+}
+
+/*====================================================================*/
+/* Solver representation: */
+
+typedef struct /* clause_t */
+{
+    int size_learnt;
+    lit lits[1];
+} clause;
+
+typedef struct /* stats_t */
+{
+    double   starts, decisions, propagations, inspects, conflicts;
+    double   clauses, clauses_literals, learnts, learnts_literals,
+             max_literals, tot_literals;
+} stats;
+
+typedef struct /* solver_t */
+{
+    int      size;          /* nof variables */
+    int      cap;           /* size of varmaps */
+    int      qhead;         /* Head index of queue. */
+    int      qtail;         /* Tail index of queue. */
+
+    /* clauses */
+    vecp     clauses;       /* List of problem constraints.
+                               (contains: clause*) */
+    vecp     learnts;       /* List of learnt clauses.
+                               (contains: clause*) */
+
+    /* activities */
+    double   var_inc;       /* Amount to bump next variable with. */
+    double   var_decay;     /* INVERSE decay factor for variable
+                               activity: stores 1/decay. */
+    float    cla_inc;       /* Amount to bump next clause with. */
+    float    cla_decay;     /* INVERSE decay factor for clause
+                               activity: stores 1/decay. */
+
+    vecp*    wlists;
+    double*  activity;      /* A heuristic measurement of the activity
+                               of a variable. */
+    lbool*   assigns;       /* Current values of variables. */
+    int*     orderpos;      /* Index in variable order. */
+    clause** reasons;
+    int*     levels;
+    lit*     trail;
+
+    clause*  binary;        /* A temporary binary clause */
+    lbool*   tags;
+    veci     tagged;        /* (contains: var) */
+    veci     stack;         /* (contains: var) */
+
+    veci     order;         /* Variable order. (heap) (contains: var) */
+    veci     trail_lim;     /* Separator indices for different decision
+                               levels in 'trail'. (contains: int) */
+    veci     model;         /* If problem is solved, this vector
+                               contains the model (contains: lbool). */
+
+    int      root_level;    /* Level of first proper decision. */
+    int      simpdb_assigns;/* Number of top-level assignments at last
+                               'simplifyDB()'. */
+    int      simpdb_props;  /* Number of propagations before next
+                               'simplifyDB()'. */
+    double   random_seed;
+    double   progress_estimate;
+    int      verbosity;     /* Verbosity level.
+                               0=silent,
+                               1=some progress report,
+                               2=everything */
+
+    stats    stats;
+} solver;
+
+/*====================================================================*/
+/* Public interface: */
+
+#if 1 /* by mao; to keep namespace clean */
+#define solver_new        _glp_minisat_new
+#define solver_delete     _glp_minisat_delete
+#define solver_addclause  _glp_minisat_addclause
+#define solver_simplify   _glp_minisat_simplify
+#define solver_solve      _glp_minisat_solve
+#define solver_nvars      _glp_minisat_nvars
+#define solver_nclauses   _glp_minisat_nclauses
+#define solver_nconflicts _glp_minisat_nconflicts
+#define solver_setnvars   _glp_minisat_setnvars
+#define solver_propagate  _glp_minisat_propagate
+#define solver_reducedb   _glp_minisat_reducedb
+#endif
+
+solver* solver_new(void);
+void    solver_delete(solver* s);
+
+bool    solver_addclause(solver* s, lit* begin, lit* end);
+bool    solver_simplify(solver* s);
+bool    solver_solve(solver* s, lit* begin, lit* end);
+
+int     solver_nvars(solver* s);
+int     solver_nclauses(solver* s);
+int     solver_nconflicts(solver* s);
+
+void    solver_setnvars(solver* s,int n);
+
+#endif
+
+/* eof */
Index: deps/glpk/src/zlib/README
===================================================================
--- deps/glpk/src/zlib/README	(revision 9)
+++ deps/glpk/src/zlib/README	(revision 9)
@@ -0,0 +1,45 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+      are used with GLPK.
+
+      The original code was modified according to GLPK requirements by
+      Andrew Makhorin <mao@gnu.org>.
+
+      The following files were rewritten:
+      gzguts.h, zconf.h, zutil.h.
+
+      The following files were added:
+      zio.h, zio.c.
+
+      Other files were not changed.
+************************************************************************
+zlib general purpose compression library
+version 1.2.5, April 19th, 2010
+
+Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would
+   be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+   distribution.
+
+Jean-loup Gailly        Mark Adler
+jloup@gzip.org          madler@alumni.caltech.edu
+
+The data format used by the zlib library is described by RFCs (Request
+for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+format) and rfc1952.txt (gzip format).
Index: deps/glpk/src/zlib/adler32.c
===================================================================
--- deps/glpk/src/zlib/adler32.c	(revision 9)
+++ deps/glpk/src/zlib/adler32.c	(revision 9)
@@ -0,0 +1,169 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2007 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
+
+#define BASE 65521UL    /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+#  define MOD(a) \
+    do { \
+        if (a >= (BASE << 16)) a -= (BASE << 16); \
+        if (a >= (BASE << 15)) a -= (BASE << 15); \
+        if (a >= (BASE << 14)) a -= (BASE << 14); \
+        if (a >= (BASE << 13)) a -= (BASE << 13); \
+        if (a >= (BASE << 12)) a -= (BASE << 12); \
+        if (a >= (BASE << 11)) a -= (BASE << 11); \
+        if (a >= (BASE << 10)) a -= (BASE << 10); \
+        if (a >= (BASE << 9)) a -= (BASE << 9); \
+        if (a >= (BASE << 8)) a -= (BASE << 8); \
+        if (a >= (BASE << 7)) a -= (BASE << 7); \
+        if (a >= (BASE << 6)) a -= (BASE << 6); \
+        if (a >= (BASE << 5)) a -= (BASE << 5); \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD4(a) \
+    do { \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD4(sum2);             /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    rem = (unsigned)(len2 % BASE);
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+    if (sum2 >= BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
Index: deps/glpk/src/zlib/compress.c
===================================================================
--- deps/glpk/src/zlib/compress.c	(revision 9)
+++ deps/glpk/src/zlib/compress.c	(revision 9)
@@ -0,0 +1,80 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+    uLong sourceLen;
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13;
+}
Index: deps/glpk/src/zlib/crc32.c
===================================================================
--- deps/glpk/src/zlib/crc32.c	(revision 9)
+++ deps/glpk/src/zlib/crc32.c	(revision 9)
@@ -0,0 +1,442 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+#  ifdef STDC           /* need ANSI C limits.h to determine sizes */
+#    include <limits.h>
+#    define BYFOUR
+#    if (UINT_MAX == 0xffffffffUL)
+       typedef unsigned int u4;
+#    else
+#      if (ULONG_MAX == 0xffffffffUL)
+         typedef unsigned long u4;
+#      else
+#        if (USHRT_MAX == 0xffffffffUL)
+           typedef unsigned short u4;
+#        else
+#          undef BYFOUR     /* can't find a four-byte integer type! */
+#        endif
+#      endif
+#    endif
+#  endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+#  define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \
+                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2);
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    unsigned long c;
+    int n, k;
+    unsigned long poly;                 /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0UL;
+        for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+            poly |= 1UL << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (unsigned long)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = REV(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = REV(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const unsigned long FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const unsigned long FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ", table[n],
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        u4 endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+#endif /* BYFOUR */
+    crc = crc ^ 0xffffffffUL;
+    while (len >= 8) {
+        DO8;
+        len -= 8;
+    }
+    if (len) do {
+        DO1;
+    } while (--len);
+    return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = (u4)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = REV((u4)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    buf4--;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf4++;
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+    unsigned long *mat;
+    unsigned long vec;
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+    unsigned long *square;
+    unsigned long *mat;
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case (also disallow negative lengths) */
+    if (len2 <= 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320UL;          /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
Index: deps/glpk/src/zlib/crc32.h
===================================================================
--- deps/glpk/src/zlib/crc32.h	(revision 9)
+++ deps/glpk/src/zlib/crc32.h	(revision 9)
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
Index: deps/glpk/src/zlib/deflate.c
===================================================================
--- deps/glpk/src/zlib/deflate.c	(revision 9)
+++ deps/glpk/src/zlib/deflate.c	(revision 9)
@@ -0,0 +1,1834 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle    OF((deflate_state *s, int flush));
+local block_state deflate_huff   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->high_water = 0;      /* nothing written to s->window yet */
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->wrap == 2 ||
+        (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+        return Z_STREAM_ERROR;
+
+    s = strm->state;
+    if (s->wrap)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > s->w_size) {
+        length = s->w_size;
+        dictionary += dictLength - length; /* use the tail of the dictionary */
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+        INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+    z_streamp strm;
+    gz_headerp head;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+    z_streamp strm;
+    int bits;
+    int value;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    strm->state->bi_valid = bits;
+    strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if ((strategy != s->strategy || func != configuration_table[level].func) &&
+        strm->total_in != 0) {
+        /* Flush the last buffer: */
+        err = deflate(strm, Z_BLOCK);
+    }
+    if (s->level != level) {
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+    z_streamp strm;
+    int good_length;
+    int max_lazy;
+    int nice_length;
+    int max_chain;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = good_length;
+    s->max_lazy_match = max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel.  But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+    z_streamp strm;
+    uLong sourceLen;
+{
+    deflate_state *s;
+    uLong complen, wraplen;
+    Bytef *str;
+
+    /* conservative upper bound for compressed data */
+    complen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+    /* if can't get parameters, return conservative bound plus zlib wrapper */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return complen + 6;
+
+    /* compute wrapper length */
+    s = strm->state;
+    switch (s->wrap) {
+    case 0:                                 /* raw deflate */
+        wraplen = 0;
+        break;
+    case 1:                                 /* zlib wrapper */
+        wraplen = 6 + (s->strstart ? 4 : 0);
+        break;
+    case 2:                                 /* gzip wrapper */
+        wraplen = 18;
+        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */
+            if (s->gzhead->extra != Z_NULL)
+                wraplen += 2 + s->gzhead->extra_len;
+            str = s->gzhead->name;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            str = s->gzhead->comment;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            if (s->gzhead->hcrc)
+                wraplen += 2;
+        }
+        break;
+    default:                                /* for compiler happiness */
+        wraplen = 6;
+    }
+
+    /* if not default parameters, return conservative bound */
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return complen + wraplen;
+
+    /* default settings: return tight bound for that case */
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        flush > Z_BLOCK || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+#ifdef GZIP
+        if (s->wrap == 2) {
+            strm->adler = crc32(0L, Z_NULL, 0);
+            put_byte(s, 31);
+            put_byte(s, 139);
+            put_byte(s, 8);
+            if (s->gzhead == Z_NULL) {
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, OS_CODE);
+                s->status = BUSY_STATE;
+            }
+            else {
+                put_byte(s, (s->gzhead->text ? 1 : 0) +
+                            (s->gzhead->hcrc ? 2 : 0) +
+                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                            (s->gzhead->name == Z_NULL ? 0 : 8) +
+                            (s->gzhead->comment == Z_NULL ? 0 : 16)
+                        );
+                put_byte(s, (Byte)(s->gzhead->time & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, s->gzhead->os & 0xff);
+                if (s->gzhead->extra != Z_NULL) {
+                    put_byte(s, s->gzhead->extra_len & 0xff);
+                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+                }
+                if (s->gzhead->hcrc)
+                    strm->adler = crc32(strm->adler, s->pending_buf,
+                                        s->pending);
+                s->gzindex = 0;
+                s->status = EXTRA_STATE;
+            }
+        }
+        else
+#endif
+        {
+            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+            uInt level_flags;
+
+            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+                level_flags = 0;
+            else if (s->level < 6)
+                level_flags = 1;
+            else if (s->level == 6)
+                level_flags = 2;
+            else
+                level_flags = 3;
+            header |= (level_flags << 6);
+            if (s->strstart != 0) header |= PRESET_DICT;
+            header += 31 - (header % 31);
+
+            s->status = BUSY_STATE;
+            putShortMSB(s, header);
+
+            /* Save the adler32 of the preset dictionary: */
+            if (s->strstart != 0) {
+                putShortMSB(s, (uInt)(strm->adler >> 16));
+                putShortMSB(s, (uInt)(strm->adler & 0xffff));
+            }
+            strm->adler = adler32(0L, Z_NULL, 0);
+        }
+    }
+#ifdef GZIP
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+
+            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size)
+                        break;
+                }
+                put_byte(s, s->gzhead->extra[s->gzindex]);
+                s->gzindex++;
+            }
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (s->gzindex == s->gzhead->extra_len) {
+                s->gzindex = 0;
+                s->status = NAME_STATE;
+            }
+        }
+        else
+            s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0) {
+                s->gzindex = 0;
+                s->status = COMMENT_STATE;
+            }
+        }
+        else
+            s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0)
+                s->status = HCRC_STATE;
+        }
+        else
+            s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size)
+                flush_pending(strm);
+            if (s->pending + 2 <= s->pending_buf_size) {
+                put_byte(s, (Byte)(strm->adler & 0xff));
+                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+                strm->adler = crc32(0L, Z_NULL, 0);
+                s->status = BUSY_STATE;
+            }
+        }
+        else
+            s->status = BUSY_STATE;
+    }
+#endif
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+                    (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+                        (*(configuration_table[s->level].func))(s, flush));
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                    if (s->lookahead == 0) {
+                        s->strstart = 0;
+                        s->block_start = 0L;
+                    }
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE &&
+        status != EXTRA_STATE &&
+        status != NAME_STATE &&
+        status != COMMENT_STATE &&
+        status != HCRC_STATE &&
+        status != BUSY_STATE &&
+        status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy(dest, source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, strm->next_in, len);
+    }
+#endif
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+#ifndef FASTEST
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+    /* If the WIN_INIT bytes after the end of the current data have never been
+     * written, then zero those bytes in order to avoid memory check reports of
+     * the use of uninitialized (or uninitialised as Julian writes) bytes by
+     * the longest match routines.  Update the high water mark for the next
+     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
+     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+     */
+    if (s->high_water < s->window_size) {
+        ulg curr = s->strstart + (ulg)(s->lookahead);
+        ulg init;
+
+        if (s->high_water < curr) {
+            /* Previous high water mark below current data -- zero WIN_INIT
+             * bytes or up to end of window, whichever is less.
+             */
+            init = s->window_size - curr;
+            if (init > WIN_INIT)
+                init = WIN_INIT;
+            zmemzero(s->window + curr, (unsigned)init);
+            s->high_water = curr + init;
+        }
+        else if (s->high_water < (ulg)curr + WIN_INIT) {
+            /* High water mark at or above current data, but below current data
+             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+             * to end of window, whichever is less.
+             */
+            init = (ulg)curr + WIN_INIT - s->high_water;
+            if (init > s->window_size - s->high_water)
+                init = s->window_size - s->high_water;
+            zmemzero(s->window + s->high_water, (unsigned)init);
+            s->high_water += init;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (last)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+   FLUSH_BLOCK_ONLY(s, last); \
+   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+        Assert(s->block_start >= 0L, "block gone");
+
+        s->strstart += s->lookahead;
+        s->lookahead = 0;
+
+        /* Emit a stored block if pending_buf will be full: */
+        max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+            /* strstart == 0 is possible when wraparound on 16-bit machine */
+            s->lookahead = (uInt)(s->strstart - max_start);
+            s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+        }
+        /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+        }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;       /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;          /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+    uInt prev;              /* byte at distance one to match */
+    Bytef *scan, *strend;   /* scan goes up to strend for length of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest encodable run.
+         */
+        if (s->lookahead < MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        s->match_length = 0;
+        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+            scan = s->window + s->strstart - 1;
+            prev = *scan;
+            if (prev == *++scan && prev == *++scan && prev == *++scan) {
+                strend = s->window + s->strstart + MAX_MATCH;
+                do {
+                } while (prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         scan < strend);
+                s->match_length = MAX_MATCH - (int)(strend - scan);
+                if (s->match_length > s->lookahead)
+                    s->match_length = s->lookahead;
+            }
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+            s->strstart += s->match_length;
+            s->match_length = 0;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we have a literal to write. */
+        if (s->lookahead == 0) {
+            fill_window(s);
+            if (s->lookahead == 0) {
+                if (flush == Z_NO_FLUSH)
+                    return need_more;
+                break;      /* flush the current block */
+            }
+        }
+
+        /* Output a literal byte */
+        s->match_length = 0;
+        Tracevv((stderr,"%c", s->window[s->strstart]));
+        _tr_tally_lit (s, s->window[s->strstart], bflush);
+        s->lookahead--;
+        s->strstart++;
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
Index: deps/glpk/src/zlib/deflate.h
===================================================================
--- deps/glpk/src/zlib/deflate.h	(revision 9)
+++ deps/glpk/src/zlib/deflate.h	(revision 9)
@@ -0,0 +1,342 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define EXTRA_STATE   69
+#define NAME_STATE    73
+#define COMMENT_STATE 91
+#define HCRC_STATE   103
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    uInt   pending;      /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    uInt   gzindex;      /* where in extra, name, or comment */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+    ulg high_water;
+    /* High water mark offset in window for initialized bytes -- bytes above
+     * this are set to zero in order to avoid memory check warnings when
+     * longest match routines access bytes past the input.  This is then
+     * updated to the new high water mark.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+   memory checker errors from longest match routines */
+
+        /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch ZLIB_INTERNAL _length_code[];
+  extern uch ZLIB_INTERNAL _dist_code[];
+#else
+  extern const uch ZLIB_INTERNAL _length_code[];
+  extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
Index: deps/glpk/src/zlib/gzclose.c
===================================================================
--- deps/glpk/src/zlib/gzclose.c	(revision 9)
+++ deps/glpk/src/zlib/gzclose.c	(revision 9)
@@ -0,0 +1,25 @@
+/* gzclose.c -- zlib gzclose() function
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* gzclose() is in a separate file so that it is linked in only if it is used.
+   That way the other gzclose functions can be used instead to avoid linking in
+   unneeded compression or decompression routines. */
+int ZEXPORT gzclose(file)
+    gzFile file;
+{
+#ifndef NO_GZCOMPRESS
+    gz_statep state;
+
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);
+#else
+    return gzclose_r(file);
+#endif
+}
Index: deps/glpk/src/zlib/gzguts.h
===================================================================
--- deps/glpk/src/zlib/gzguts.h	(revision 9)
+++ deps/glpk/src/zlib/gzguts.h	(revision 9)
@@ -0,0 +1,74 @@
+/* gzguts.h (zlib internal header definitions for gz* operations) */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, April 2011 */
+
+/* Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h. */
+
+#ifndef GZGUTS_H
+#define GZGUTS_H
+
+#define ZLIB_INTERNAL
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zio.h"
+#include "zlib.h"
+
+#define local static
+
+#define zstrerror() strerror(errno)
+
+#define GZBUFSIZE 8192
+
+#define GZ_NONE 0
+#define GZ_READ 7247
+#define GZ_WRITE 31153
+#define GZ_APPEND 1
+
+#define LOOK 0
+#define COPY 1
+#define GZIP 2
+
+typedef struct
+{     int mode;
+      int fd;
+      char *path;
+      z_off64_t pos;
+      unsigned size;
+      unsigned want;
+      unsigned char *in;
+      unsigned char *out;
+      unsigned char *next;
+      unsigned have;
+      int eof;
+      z_off64_t start;
+      z_off64_t raw;
+      int how;
+      int direct;
+      int level;
+      int strategy;
+      z_off64_t skip;
+      int seek;
+      int err;
+      char *msg;
+      z_stream strm;
+} gz_state;
+
+typedef gz_state *gz_statep;
+
+void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
+
+#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
+
+#endif
+
+/* eof */
Index: deps/glpk/src/zlib/gzlib.c
===================================================================
--- deps/glpk/src/zlib/gzlib.c	(revision 9)
+++ deps/glpk/src/zlib/gzlib.c	(revision 9)
@@ -0,0 +1,537 @@
+/* gzlib.c -- zlib functions common to reading and writing gzip files
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+#  define LSEEK lseek64
+#else
+#  define LSEEK lseek
+#endif
+
+/* Local functions */
+local void gz_reset OF((gz_statep));
+local gzFile gz_open OF((const char *, int, const char *));
+
+#if defined UNDER_CE
+
+/* Map the Windows error number in ERROR to a locale-dependent error message
+   string and return a pointer to it.  Typically, the values for ERROR come
+   from GetLastError.
+
+   The string pointed to shall not be modified by the application, but may be
+   overwritten by a subsequent call to gz_strwinerror
+
+   The gz_strwinerror function does not change the current setting of
+   GetLastError. */
+char ZLIB_INTERNAL *gz_strwinerror (error)
+     DWORD error;
+{
+    static char buf[1024];
+
+    wchar_t *msgbuf;
+    DWORD lasterr = GetLastError();
+    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+        NULL,
+        error,
+        0, /* Default language */
+        (LPVOID)&msgbuf,
+        0,
+        NULL);
+    if (chars != 0) {
+        /* If there is an \r\n appended, zap it.  */
+        if (chars >= 2
+            && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
+            chars -= 2;
+            msgbuf[chars] = 0;
+        }
+
+        if (chars > sizeof (buf) - 1) {
+            chars = sizeof (buf) - 1;
+            msgbuf[chars] = 0;
+        }
+
+        wcstombs(buf, msgbuf, chars + 1);
+        LocalFree(msgbuf);
+    }
+    else {
+        sprintf(buf, "unknown win32 error (%ld)", error);
+    }
+
+    SetLastError(lasterr);
+    return buf;
+}
+
+#endif /* UNDER_CE */
+
+/* Reset gzip file state */
+local void gz_reset(state)
+    gz_statep state;
+{
+    if (state->mode == GZ_READ) {   /* for reading ... */
+        state->have = 0;            /* no output data available */
+        state->eof = 0;             /* not at end of file */
+        state->how = LOOK;          /* look for gzip header */
+        state->direct = 1;          /* default for empty file */
+    }
+    state->seek = 0;                /* no seek request pending */
+    gz_error(state, Z_OK, NULL);    /* clear error */
+    state->pos = 0;                 /* no uncompressed data yet */
+    state->strm.avail_in = 0;       /* no input data yet */
+}
+
+/* Open a gzip file either by name or file descriptor. */
+local gzFile gz_open(path, fd, mode)
+    const char *path;
+    int fd;
+    const char *mode;
+{
+    gz_statep state;
+
+    /* allocate gzFile structure to return */
+    state = malloc(sizeof(gz_state));
+    if (state == NULL)
+        return NULL;
+    state->size = 0;            /* no buffers allocated yet */
+    state->want = GZBUFSIZE;    /* requested buffer size */
+    state->msg = NULL;          /* no error message yet */
+
+    /* interpret mode */
+    state->mode = GZ_NONE;
+    state->level = Z_DEFAULT_COMPRESSION;
+    state->strategy = Z_DEFAULT_STRATEGY;
+    while (*mode) {
+        if (*mode >= '0' && *mode <= '9')
+            state->level = *mode - '0';
+        else
+            switch (*mode) {
+            case 'r':
+                state->mode = GZ_READ;
+                break;
+#ifndef NO_GZCOMPRESS
+            case 'w':
+                state->mode = GZ_WRITE;
+                break;
+            case 'a':
+                state->mode = GZ_APPEND;
+                break;
+#endif
+            case '+':       /* can't read and write at the same time */
+                free(state);
+                return NULL;
+            case 'b':       /* ignore -- will request binary anyway */
+                break;
+            case 'f':
+                state->strategy = Z_FILTERED;
+                break;
+            case 'h':
+                state->strategy = Z_HUFFMAN_ONLY;
+                break;
+            case 'R':
+                state->strategy = Z_RLE;
+                break;
+            case 'F':
+                state->strategy = Z_FIXED;
+            default:        /* could consider as an error, but just ignore */
+                ;
+            }
+        mode++;
+    }
+
+    /* must provide an "r", "w", or "a" */
+    if (state->mode == GZ_NONE) {
+        free(state);
+        return NULL;
+    }
+
+    /* save the path name for error messages */
+    state->path = malloc(strlen(path) + 1);
+    if (state->path == NULL) {
+        free(state);
+        return NULL;
+    }
+    strcpy(state->path, path);
+
+    /* open the file with the appropriate mode (or just use fd) */
+    state->fd = fd != -1 ? fd :
+        open(path,
+#ifdef O_LARGEFILE
+            O_LARGEFILE |
+#endif
+#ifdef O_BINARY
+            O_BINARY |
+#endif
+            (state->mode == GZ_READ ?
+                O_RDONLY :
+                (O_WRONLY | O_CREAT | (
+                    state->mode == GZ_WRITE ?
+                        O_TRUNC :
+                        O_APPEND))),
+            0666);
+    if (state->fd == -1) {
+        free(state->path);
+        free(state);
+        return NULL;
+    }
+    if (state->mode == GZ_APPEND)
+        state->mode = GZ_WRITE;         /* simplify later checks */
+
+    /* save the current position for rewinding (only if reading) */
+    if (state->mode == GZ_READ) {
+        state->start = LSEEK(state->fd, 0, SEEK_CUR);
+        if (state->start == -1) state->start = 0;
+    }
+
+    /* initialize stream */
+    gz_reset(state);
+
+    /* return stream */
+    return (gzFile)state;
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen(path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen64(path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzdopen(fd, mode)
+    int fd;
+    const char *mode;
+{
+    char *path;         /* identifier for error messages */
+    gzFile gz;
+
+    if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
+        return NULL;
+    sprintf(path, "<fd:%d>", fd);   /* for debugging */
+    gz = gz_open(path, fd, mode);
+    free(path);
+    return gz;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzbuffer(file, size)
+    gzFile file;
+    unsigned size;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* make sure we haven't already allocated memory */
+    if (state->size != 0)
+        return -1;
+
+    /* check and set requested size */
+    if (size == 0)
+        return -1;
+    state->want = size;
+    return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzrewind(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* back up and start over */
+    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
+        return -1;
+    gz_reset(state);
+    return 0;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzseek64(file, offset, whence)
+    gzFile file;
+    z_off64_t offset;
+    int whence;
+{
+    unsigned n;
+    z_off64_t ret;
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* check that there's no error */
+    if (state->err != Z_OK)
+        return -1;
+
+    /* can only seek from start or relative to current position */
+    if (whence != SEEK_SET && whence != SEEK_CUR)
+        return -1;
+
+    /* normalize offset to a SEEK_CUR specification */
+    if (whence == SEEK_SET)
+        offset -= state->pos;
+    else if (state->seek)
+        offset += state->skip;
+    state->seek = 0;
+
+    /* if within raw area while reading, just go there */
+    if (state->mode == GZ_READ && state->how == COPY &&
+        state->pos + offset >= state->raw) {
+        ret = LSEEK(state->fd, offset - state->have, SEEK_CUR);
+        if (ret == -1)
+            return -1;
+        state->have = 0;
+        state->eof = 0;
+        state->seek = 0;
+        gz_error(state, Z_OK, NULL);
+        state->strm.avail_in = 0;
+        state->pos += offset;
+        return state->pos;
+    }
+
+    /* calculate skip amount, rewinding if needed for back seek when reading */
+    if (offset < 0) {
+        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
+            return -1;
+        offset += state->pos;
+        if (offset < 0)                     /* before start of file! */
+            return -1;
+        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
+            return -1;
+    }
+
+    /* if reading, skip what's in output buffer (one less gzgetc() check) */
+    if (state->mode == GZ_READ) {
+        n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?
+            (unsigned)offset : state->have;
+        state->have -= n;
+        state->next += n;
+        state->pos += n;
+        offset -= n;
+    }
+
+    /* request skip (if not zero) */
+    if (offset) {
+        state->seek = 1;
+        state->skip = offset;
+    }
+    return state->pos + offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzseek(file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    z_off64_t ret;
+
+    ret = gzseek64(file, (z_off64_t)offset, whence);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gztell64(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* return position */
+    return state->pos + (state->seek ? state->skip : 0);
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gztell(file)
+    gzFile file;
+{
+    z_off64_t ret;
+
+    ret = gztell64(file);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzoffset64(file)
+    gzFile file;
+{
+    z_off64_t offset;
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* compute and return effective offset in file */
+    offset = LSEEK(state->fd, 0, SEEK_CUR);
+    if (offset == -1)
+        return -1;
+    if (state->mode == GZ_READ)             /* reading */
+        offset -= state->strm.avail_in;     /* don't count buffered input */
+    return offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzoffset(file)
+    gzFile file;
+{
+    z_off64_t ret;
+
+    ret = gzoffset64(file);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzeof(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return 0;
+
+    /* return end-of-file state */
+    return state->mode == GZ_READ ?
+        (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0;
+}
+
+/* -- see zlib.h -- */
+const char * ZEXPORT gzerror(file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return NULL;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return NULL;
+
+    /* return error information */
+    if (errnum != NULL)
+        *errnum = state->err;
+    return state->msg == NULL ? "" : state->msg;
+}
+
+/* -- see zlib.h -- */
+void ZEXPORT gzclearerr(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return;
+
+    /* clear error and end-of-file */
+    if (state->mode == GZ_READ)
+        state->eof = 0;
+    gz_error(state, Z_OK, NULL);
+}
+
+/* Create an error message in allocated memory and set state->err and
+   state->msg accordingly.  Free any previous error message already there.  Do
+   not try to free or allocate space if the error is Z_MEM_ERROR (out of
+   memory).  Simply save the error message as a static string.  If there is an
+   allocation failure constructing the error message, then convert the error to
+   out of memory. */
+void ZLIB_INTERNAL gz_error(state, err, msg)
+    gz_statep state;
+    int err;
+    const char *msg;
+{
+    /* free previously allocated message and clear */
+    if (state->msg != NULL) {
+        if (state->err != Z_MEM_ERROR)
+            free(state->msg);
+        state->msg = NULL;
+    }
+
+    /* set error code, and if no message, then done */
+    state->err = err;
+    if (msg == NULL)
+        return;
+
+    /* for an out of memory error, save as static string */
+    if (err == Z_MEM_ERROR) {
+        state->msg = (char *)msg;
+        return;
+    }
+
+    /* construct error message with path */
+    if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
+        state->err = Z_MEM_ERROR;
+        state->msg = (char *)"out of memory";
+        return;
+    }
+    strcpy(state->msg, state->path);
+    strcat(state->msg, ": ");
+    strcat(state->msg, msg);
+    return;
+}
+
+#ifndef INT_MAX
+/* portably return maximum value for an int (when limits.h presumed not
+   available) -- we need to do this to cover cases where 2's complement not
+   used, since C standard permits 1's complement and sign-bit representations,
+   otherwise we could just use ((unsigned)-1) >> 1 */
+unsigned ZLIB_INTERNAL gz_intmax()
+{
+    unsigned p, q;
+
+    p = 1;
+    do {
+        q = p;
+        p <<= 1;
+        p++;
+    } while (p > q);
+    return q >> 1;
+}
+#endif
Index: deps/glpk/src/zlib/gzread.c
===================================================================
--- deps/glpk/src/zlib/gzread.c	(revision 9)
+++ deps/glpk/src/zlib/gzread.c	(revision 9)
@@ -0,0 +1,653 @@
+/* gzread.c -- zlib functions for reading gzip files
+ * Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
+local int gz_avail OF((gz_statep));
+local int gz_next4 OF((gz_statep, unsigned long *));
+local int gz_head OF((gz_statep));
+local int gz_decomp OF((gz_statep));
+local int gz_make OF((gz_statep));
+local int gz_skip OF((gz_statep, z_off64_t));
+
+/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
+   state->fd, and update state->eof, state->err, and state->msg as appropriate.
+   This function needs to loop on read(), since read() is not guaranteed to
+   read the number of bytes requested, depending on the type of descriptor. */
+local int gz_load(state, buf, len, have)
+    gz_statep state;
+    unsigned char *buf;
+    unsigned len;
+    unsigned *have;
+{
+    int ret;
+
+    *have = 0;
+    do {
+        ret = read(state->fd, buf + *have, len - *have);
+        if (ret <= 0)
+            break;
+        *have += ret;
+    } while (*have < len);
+    if (ret < 0) {
+        gz_error(state, Z_ERRNO, zstrerror());
+        return -1;
+    }
+    if (ret == 0)
+        state->eof = 1;
+    return 0;
+}
+
+/* Load up input buffer and set eof flag if last data loaded -- return -1 on
+   error, 0 otherwise.  Note that the eof flag is set when the end of the input
+   file is reached, even though there may be unused data in the buffer.  Once
+   that data has been used, no more attempts will be made to read the file.
+   gz_avail() assumes that strm->avail_in == 0. */
+local int gz_avail(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+
+    if (state->err != Z_OK)
+        return -1;
+    if (state->eof == 0) {
+        if (gz_load(state, state->in, state->size,
+                (unsigned *)&(strm->avail_in)) == -1)
+            return -1;
+        strm->next_in = state->in;
+    }
+    return 0;
+}
+
+/* Get next byte from input, or -1 if end or error. */
+#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \
+                (strm->avail_in == 0 ? -1 : \
+                 (strm->avail_in--, *(strm->next_in)++)))
+
+/* Get a four-byte little-endian integer and return 0 on success and the value
+   in *ret.  Otherwise -1 is returned and *ret is not modified. */
+local int gz_next4(state, ret)
+    gz_statep state;
+    unsigned long *ret;
+{
+    int ch;
+    unsigned long val;
+    z_streamp strm = &(state->strm);
+
+    val = NEXT();
+    val += (unsigned)NEXT() << 8;
+    val += (unsigned long)NEXT() << 16;
+    ch = NEXT();
+    if (ch == -1)
+        return -1;
+    val += (unsigned long)ch << 24;
+    *ret = val;
+    return 0;
+}
+
+/* Look for gzip header, set up for inflate or copy.  state->have must be zero.
+   If this is the first time in, allocate required memory.  state->how will be
+   left unchanged if there is no more input data available, will be set to COPY
+   if there is no gzip header and direct copying will be performed, or it will
+   be set to GZIP for decompression, and the gzip header will be skipped so
+   that the next available input data is the raw deflate stream.  If direct
+   copying, then leftover input data from the input buffer will be copied to
+   the output buffer.  In that case, all further file reads will be directly to
+   either the output buffer or a user buffer.  If decompressing, the inflate
+   state and the check value will be initialized.  gz_head() will return 0 on
+   success or -1 on failure.  Failures may include read errors or gzip header
+   errors.  */
+local int gz_head(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+    int flags;
+    unsigned len;
+
+    /* allocate read buffers and inflate memory */
+    if (state->size == 0) {
+        /* allocate buffers */
+        state->in = malloc(state->want);
+        state->out = malloc(state->want << 1);
+        if (state->in == NULL || state->out == NULL) {
+            if (state->out != NULL)
+                free(state->out);
+            if (state->in != NULL)
+                free(state->in);
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+        state->size = state->want;
+
+        /* allocate inflate memory */
+        state->strm.zalloc = Z_NULL;
+        state->strm.zfree = Z_NULL;
+        state->strm.opaque = Z_NULL;
+        state->strm.avail_in = 0;
+        state->strm.next_in = Z_NULL;
+        if (inflateInit2(&(state->strm), -15) != Z_OK) {    /* raw inflate */
+            free(state->out);
+            free(state->in);
+            state->size = 0;
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+    }
+
+    /* get some data in the input buffer */
+    if (strm->avail_in == 0) {
+        if (gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in == 0)
+            return 0;
+    }
+
+    /* look for the gzip magic header bytes 31 and 139 */
+    if (strm->next_in[0] == 31) {
+        strm->avail_in--;
+        strm->next_in++;
+        if (strm->avail_in == 0 && gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in && strm->next_in[0] == 139) {
+            /* we have a gzip header, woo hoo! */
+            strm->avail_in--;
+            strm->next_in++;
+
+            /* skip rest of header */
+            if (NEXT() != 8) {      /* compression method */
+                gz_error(state, Z_DATA_ERROR, "unknown compression method");
+                return -1;
+            }
+            flags = NEXT();
+            if (flags & 0xe0) {     /* reserved flag bits */
+                gz_error(state, Z_DATA_ERROR, "unknown header flags set");
+                return -1;
+            }
+            NEXT();                 /* modification time */
+            NEXT();
+            NEXT();
+            NEXT();
+            NEXT();                 /* extra flags */
+            NEXT();                 /* operating system */
+            if (flags & 4) {        /* extra field */
+                len = (unsigned)NEXT();
+                len += (unsigned)NEXT() << 8;
+                while (len--)
+                    if (NEXT() < 0)
+                        break;
+            }
+            if (flags & 8)          /* file name */
+                while (NEXT() > 0)
+                    ;
+            if (flags & 16)         /* comment */
+                while (NEXT() > 0)
+                    ;
+            if (flags & 2) {        /* header crc */
+                NEXT();
+                NEXT();
+            }
+            /* an unexpected end of file is not checked for here -- it will be
+               noticed on the first request for uncompressed data */
+
+            /* set up for decompression */
+            inflateReset(strm);
+            strm->adler = crc32(0L, Z_NULL, 0);
+            state->how = GZIP;
+            state->direct = 0;
+            return 0;
+        }
+        else {
+            /* not a gzip file -- save first byte (31) and fall to raw i/o */
+            state->out[0] = 31;
+            state->have = 1;
+        }
+    }
+
+    /* doing raw i/o, save start of raw data for seeking, copy any leftover
+       input to output -- this assumes that the output buffer is larger than
+       the input buffer, which also assures space for gzungetc() */
+    state->raw = state->pos;
+    state->next = state->out;
+    if (strm->avail_in) {
+        memcpy(state->next + state->have, strm->next_in, strm->avail_in);
+        state->have += strm->avail_in;
+        strm->avail_in = 0;
+    }
+    state->how = COPY;
+    state->direct = 1;
+    return 0;
+}
+
+/* Decompress from input to the provided next_out and avail_out in the state.
+   If the end of the compressed data is reached, then verify the gzip trailer
+   check value and length (modulo 2^32).  state->have and state->next are set
+   to point to the just decompressed data, and the crc is updated.  If the
+   trailer is verified, state->how is reset to LOOK to look for the next gzip
+   stream or raw data, once state->have is depleted.  Returns 0 on success, -1
+   on failure.  Failures may include invalid compressed data or a failed gzip
+   trailer verification. */
+local int gz_decomp(state)
+    gz_statep state;
+{
+    int ret;
+    unsigned had;
+    unsigned long crc, len;
+    z_streamp strm = &(state->strm);
+
+    /* fill output buffer up to end of deflate stream */
+    had = strm->avail_out;
+    do {
+        /* get more input for inflate() */
+        if (strm->avail_in == 0 && gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in == 0) {
+            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
+            return -1;
+        }
+
+        /* decompress and handle errors */
+        ret = inflate(strm, Z_NO_FLUSH);
+        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
+            gz_error(state, Z_STREAM_ERROR,
+                      "internal error: inflate stream corrupt");
+            return -1;
+        }
+        if (ret == Z_MEM_ERROR) {
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
+            gz_error(state, Z_DATA_ERROR,
+                      strm->msg == NULL ? "compressed data error" : strm->msg);
+            return -1;
+        }
+    } while (strm->avail_out && ret != Z_STREAM_END);
+
+    /* update available output and crc check value */
+    state->have = had - strm->avail_out;
+    state->next = strm->next_out - state->have;
+    strm->adler = crc32(strm->adler, state->next, state->have);
+
+    /* check gzip trailer if at end of deflate stream */
+    if (ret == Z_STREAM_END) {
+        if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) {
+            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
+            return -1;
+        }
+        if (crc != strm->adler) {
+            gz_error(state, Z_DATA_ERROR, "incorrect data check");
+            return -1;
+        }
+        if (len != (strm->total_out & 0xffffffffL)) {
+            gz_error(state, Z_DATA_ERROR, "incorrect length check");
+            return -1;
+        }
+        state->how = LOOK;      /* ready for next stream, once have is 0 (leave
+                                   state->direct unchanged to remember how) */
+    }
+
+    /* good decompression */
+    return 0;
+}
+
+/* Make data and put in the output buffer.  Assumes that state->have == 0.
+   Data is either copied from the input file or decompressed from the input
+   file depending on state->how.  If state->how is LOOK, then a gzip header is
+   looked for (and skipped if found) to determine wither to copy or decompress.
+   Returns -1 on error, otherwise 0.  gz_make() will leave state->have as COPY
+   or GZIP unless the end of the input file has been reached and all data has
+   been processed.  */
+local int gz_make(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+
+    if (state->how == LOOK) {           /* look for gzip header */
+        if (gz_head(state) == -1)
+            return -1;
+        if (state->have)                /* got some data from gz_head() */
+            return 0;
+    }
+    if (state->how == COPY) {           /* straight copy */
+        if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1)
+            return -1;
+        state->next = state->out;
+    }
+    else if (state->how == GZIP) {      /* decompress */
+        strm->avail_out = state->size << 1;
+        strm->next_out = state->out;
+        if (gz_decomp(state) == -1)
+            return -1;
+    }
+    return 0;
+}
+
+/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
+local int gz_skip(state, len)
+    gz_statep state;
+    z_off64_t len;
+{
+    unsigned n;
+
+    /* skip over len bytes or reach end-of-file, whichever comes first */
+    while (len)
+        /* skip over whatever is in output buffer */
+        if (state->have) {
+            n = GT_OFF(state->have) || (z_off64_t)state->have > len ?
+                (unsigned)len : state->have;
+            state->have -= n;
+            state->next += n;
+            state->pos += n;
+            len -= n;
+        }
+
+        /* output buffer empty -- return if we're at the end of the input */
+        else if (state->eof && state->strm.avail_in == 0)
+            break;
+
+        /* need more data to skip -- load up output buffer */
+        else {
+            /* get more output, looking for header if required */
+            if (gz_make(state) == -1)
+                return -1;
+        }
+    return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzread(file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    unsigned got, n;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* since an int is returned, make sure len fits in one, otherwise return
+       with an error (this avoids the flaw in the interface) */
+    if ((int)len < 0) {
+        gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
+        return -1;
+    }
+
+    /* if len is zero, avoid unnecessary operations */
+    if (len == 0)
+        return 0;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* get len bytes to buf, or less than len if at the end */
+    got = 0;
+    do {
+        /* first just try copying data from the output buffer */
+        if (state->have) {
+            n = state->have > len ? len : state->have;
+            memcpy(buf, state->next, n);
+            state->next += n;
+            state->have -= n;
+        }
+
+        /* output buffer empty -- return if we're at the end of the input */
+        else if (state->eof && strm->avail_in == 0)
+            break;
+
+        /* need output data -- for small len or new stream load up our output
+           buffer */
+        else if (state->how == LOOK || len < (state->size << 1)) {
+            /* get more output, looking for header if required */
+            if (gz_make(state) == -1)
+                return -1;
+            continue;       /* no progress yet -- go back to memcpy() above */
+            /* the copy above assures that we will leave with space in the
+               output buffer, allowing at least one gzungetc() to succeed */
+        }
+
+        /* large len -- read directly into user buffer */
+        else if (state->how == COPY) {      /* read directly */
+            if (gz_load(state, buf, len, &n) == -1)
+                return -1;
+        }
+
+        /* large len -- decompress directly into user buffer */
+        else {  /* state->how == GZIP */
+            strm->avail_out = len;
+            strm->next_out = buf;
+            if (gz_decomp(state) == -1)
+                return -1;
+            n = state->have;
+            state->have = 0;
+        }
+
+        /* update progress */
+        len -= n;
+        buf = (char *)buf + n;
+        got += n;
+        state->pos += n;
+    } while (len);
+
+    /* return number of bytes read into user buffer (will fit in int) */
+    return (int)got;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    int ret;
+    unsigned char buf[1];
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* try output buffer (no need to check for skip request) */
+    if (state->have) {
+        state->have--;
+        state->pos++;
+        return *(state->next)++;
+    }
+
+    /* nothing there -- try gzread() */
+    ret = gzread(file, buf, 1);
+    return ret < 1 ? -1 : buf[0];
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzungetc(c, file)
+    int c;
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* can't push EOF */
+    if (c < 0)
+        return -1;
+
+    /* if output buffer empty, put byte at end (allows more pushing) */
+    if (state->have == 0) {
+        state->have = 1;
+        state->next = state->out + (state->size << 1) - 1;
+        state->next[0] = c;
+        state->pos--;
+        return c;
+    }
+
+    /* if no room, give up (must have already done a gzungetc()) */
+    if (state->have == (state->size << 1)) {
+        gz_error(state, Z_BUF_ERROR, "out of room to push characters");
+        return -1;
+    }
+
+    /* slide output data if needed and insert byte before existing data */
+    if (state->next == state->out) {
+        unsigned char *src = state->out + state->have;
+        unsigned char *dest = state->out + (state->size << 1);
+        while (src > state->out)
+            *--dest = *--src;
+        state->next = dest;
+    }
+    state->have++;
+    state->next--;
+    state->next[0] = c;
+    state->pos--;
+    return c;
+}
+
+/* -- see zlib.h -- */
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    unsigned left, n;
+    char *str;
+    unsigned char *eol;
+    gz_statep state;
+
+    /* check parameters and get internal structure */
+    if (file == NULL || buf == NULL || len < 1)
+        return NULL;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return NULL;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return NULL;
+    }
+
+    /* copy output bytes up to new line or len - 1, whichever comes first --
+       append a terminating zero to the string (we don't check for a zero in
+       the contents, let the user worry about that) */
+    str = buf;
+    left = (unsigned)len - 1;
+    if (left) do {
+        /* assure that something is in the output buffer */
+        if (state->have == 0) {
+            if (gz_make(state) == -1)
+                return NULL;            /* error */
+            if (state->have == 0) {     /* end of file */
+                if (buf == str)         /* got bupkus */
+                    return NULL;
+                break;                  /* got something -- return it */
+            }
+        }
+
+        /* look for end-of-line in current output buffer */
+        n = state->have > left ? left : state->have;
+        eol = memchr(state->next, '\n', n);
+        if (eol != NULL)
+            n = (unsigned)(eol - state->next) + 1;
+
+        /* copy through end-of-line, or remainder if not found */
+        memcpy(buf, state->next, n);
+        state->have -= n;
+        state->next += n;
+        state->pos += n;
+        left -= n;
+        buf += n;
+    } while (left && eol == NULL);
+
+    /* found end-of-line or out of space -- terminate string and return it */
+    buf[0] = 0;
+    return str;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzdirect(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+
+    /* check that we're reading */
+    if (state->mode != GZ_READ)
+        return 0;
+
+    /* if the state is not known, but we can find out, then do so (this is
+       mainly for right after a gzopen() or gzdopen()) */
+    if (state->how == LOOK && state->have == 0)
+        (void)gz_head(state);
+
+    /* return 1 if reading direct, 0 if decompressing a gzip stream */
+    return state->direct;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_r(file)
+    gzFile file;
+{
+    int ret;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    /* check that we're reading */
+    if (state->mode != GZ_READ)
+        return Z_STREAM_ERROR;
+
+    /* free memory and close file */
+    if (state->size) {
+        inflateEnd(&(state->strm));
+        free(state->out);
+        free(state->in);
+    }
+    gz_error(state, Z_OK, NULL);
+    free(state->path);
+    ret = close(state->fd);
+    free(state);
+    return ret ? Z_ERRNO : Z_OK;
+}
Index: deps/glpk/src/zlib/gzwrite.c
===================================================================
--- deps/glpk/src/zlib/gzwrite.c	(revision 9)
+++ deps/glpk/src/zlib/gzwrite.c	(revision 9)
@@ -0,0 +1,531 @@
+/* gzwrite.c -- zlib functions for writing gzip files
+ * Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_init OF((gz_statep));
+local int gz_comp OF((gz_statep, int));
+local int gz_zero OF((gz_statep, z_off64_t));
+
+/* Initialize state for writing a gzip file.  Mark initialization by setting
+   state->size to non-zero.  Return -1 on failure or 0 on success. */
+local int gz_init(state)
+    gz_statep state;
+{
+    int ret;
+    z_streamp strm = &(state->strm);
+
+    /* allocate input and output buffers */
+    state->in = malloc(state->want);
+    state->out = malloc(state->want);
+    if (state->in == NULL || state->out == NULL) {
+        if (state->out != NULL)
+            free(state->out);
+        if (state->in != NULL)
+            free(state->in);
+        gz_error(state, Z_MEM_ERROR, "out of memory");
+        return -1;
+    }
+
+    /* allocate deflate memory, set up for gzip compression */
+    strm->zalloc = Z_NULL;
+    strm->zfree = Z_NULL;
+    strm->opaque = Z_NULL;
+    ret = deflateInit2(strm, state->level, Z_DEFLATED,
+                       15 + 16, 8, state->strategy);
+    if (ret != Z_OK) {
+        free(state->in);
+        gz_error(state, Z_MEM_ERROR, "out of memory");
+        return -1;
+    }
+
+    /* mark state as initialized */
+    state->size = state->want;
+
+    /* initialize write buffer */
+    strm->avail_out = state->size;
+    strm->next_out = state->out;
+    state->next = strm->next_out;
+    return 0;
+}
+
+/* Compress whatever is at avail_in and next_in and write to the output file.
+   Return -1 if there is an error writing to the output file, otherwise 0.
+   flush is assumed to be a valid deflate() flush value.  If flush is Z_FINISH,
+   then the deflate() state is reset to start a new gzip stream. */
+local int gz_comp(state, flush)
+    gz_statep state;
+    int flush;
+{
+    int ret, got;
+    unsigned have;
+    z_streamp strm = &(state->strm);
+
+    /* allocate memory if this is the first time through */
+    if (state->size == 0 && gz_init(state) == -1)
+        return -1;
+
+    /* run deflate() on provided input until it produces no more output */
+    ret = Z_OK;
+    do {
+        /* write out current buffer contents if full, or if flushing, but if
+           doing Z_FINISH then don't write until we get to Z_STREAM_END */
+        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
+            (flush != Z_FINISH || ret == Z_STREAM_END))) {
+            have = (unsigned)(strm->next_out - state->next);
+            if (have && ((got = write(state->fd, state->next, have)) < 0 ||
+                         (unsigned)got != have)) {
+                gz_error(state, Z_ERRNO, zstrerror());
+                return -1;
+            }
+            if (strm->avail_out == 0) {
+                strm->avail_out = state->size;
+                strm->next_out = state->out;
+            }
+            state->next = strm->next_out;
+        }
+
+        /* compress */
+        have = strm->avail_out;
+        ret = deflate(strm, flush);
+        if (ret == Z_STREAM_ERROR) {
+            gz_error(state, Z_STREAM_ERROR,
+                      "internal error: deflate stream corrupt");
+            return -1;
+        }
+        have -= strm->avail_out;
+    } while (have);
+
+    /* if that completed a deflate stream, allow another to start */
+    if (flush == Z_FINISH)
+        deflateReset(strm);
+
+    /* all done, no errors */
+    return 0;
+}
+
+/* Compress len zeros to output.  Return -1 on error, 0 on success. */
+local int gz_zero(state, len)
+    gz_statep state;
+    z_off64_t len;
+{
+    int first;
+    unsigned n;
+    z_streamp strm = &(state->strm);
+
+    /* consume whatever's left in the input buffer */
+    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+        return -1;
+
+    /* compress len zeros (len guaranteed > 0) */
+    first = 1;
+    while (len) {
+        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
+            (unsigned)len : state->size;
+        if (first) {
+            memset(state->in, 0, n);
+            first = 0;
+        }
+        strm->avail_in = n;
+        strm->next_in = state->in;
+        state->pos += n;
+        if (gz_comp(state, Z_NO_FLUSH) == -1)
+            return -1;
+        len -= n;
+    }
+    return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzwrite(file, buf, len)
+    gzFile file;
+    voidpc buf;
+    unsigned len;
+{
+    unsigned put = len;
+    unsigned n;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* since an int is returned, make sure len fits in one, otherwise return
+       with an error (this avoids the flaw in the interface) */
+    if ((int)len < 0) {
+        gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
+        return 0;
+    }
+
+    /* if len is zero, avoid unnecessary operations */
+    if (len == 0)
+        return 0;
+
+    /* allocate memory if this is the first time through */
+    if (state->size == 0 && gz_init(state) == -1)
+        return 0;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* for small len, copy to input buffer, otherwise compress directly */
+    if (len < state->size) {
+        /* copy to input buffer, compress when full */
+        do {
+            if (strm->avail_in == 0)
+                strm->next_in = state->in;
+            n = state->size - strm->avail_in;
+            if (n > len)
+                n = len;
+            memcpy(strm->next_in + strm->avail_in, buf, n);
+            strm->avail_in += n;
+            state->pos += n;
+            buf = (char *)buf + n;
+            len -= n;
+            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
+                return 0;
+        } while (len);
+    }
+    else {
+        /* consume whatever's left in the input buffer */
+        if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+            return 0;
+
+        /* directly compress user buffer to file */
+        strm->avail_in = len;
+        strm->next_in = (voidp)buf;
+        state->pos += len;
+        if (gz_comp(state, Z_NO_FLUSH) == -1)
+            return 0;
+    }
+
+    /* input was all buffered or compressed (put will fit in int) */
+    return (int)put;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned char buf[1];
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return -1;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* try writing to input buffer for speed (state->size == 0 if buffer not
+       initialized) */
+    if (strm->avail_in < state->size) {
+        if (strm->avail_in == 0)
+            strm->next_in = state->in;
+        strm->next_in[strm->avail_in++] = c;
+        state->pos++;
+        return c;
+    }
+
+    /* no room in buffer or not initialized, use gz_write() */
+    buf[0] = c;
+    if (gzwrite(file, buf, 1) != 1)
+        return -1;
+    return c;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputs(file, str)
+    gzFile file;
+    const char *str;
+{
+    int ret;
+    unsigned len;
+
+    /* write string */
+    len = (unsigned)strlen(str);
+    ret = gzwrite(file, str, len);
+    return ret == 0 && len != 0 ? -1 : ret;
+}
+
+#ifdef STDC
+#include <stdarg.h>
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
+{
+    int size, len;
+    gz_statep state;
+    z_streamp strm;
+    va_list va;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* make sure we have some buffer space */
+    if (state->size == 0 && gz_init(state) == -1)
+        return 0;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* consume whatever's left in the input buffer */
+    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+        return 0;
+
+    /* do the printf() into the input buffer, put length in len */
+    size = (int)(state->size);
+    state->in[size - 1] = 0;
+    va_start(va, format);
+#ifdef NO_vsnprintf
+#  ifdef HAS_vsprintf_void
+    (void)vsprintf(state->in, format, va);
+    va_end(va);
+    for (len = 0; len < size; len++)
+        if (state->in[len] == 0) break;
+#  else
+    len = vsprintf(state->in, format, va);
+    va_end(va);
+#  endif
+#else
+#  ifdef HAS_vsnprintf_void
+    (void)vsnprintf(state->in, size, format, va);
+    va_end(va);
+    len = strlen(state->in);
+#  else
+    len = vsnprintf((char *)(state->in), size, format, va);
+    va_end(va);
+#  endif
+#endif
+
+    /* check that printf() results fit in buffer */
+    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+        return 0;
+
+    /* update buffer and position, defer compression until needed */
+    strm->avail_in = (unsigned)len;
+    strm->next_in = state->in;
+    state->pos += len;
+    return len;
+}
+
+#else /* !STDC */
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    int size, len;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* make sure we have some buffer space */
+    if (state->size == 0 && gz_init(state) == -1)
+        return 0;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* consume whatever's left in the input buffer */
+    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+        return 0;
+
+    /* do the printf() into the input buffer, put length in len */
+    size = (int)(state->size);
+    state->in[size - 1] = 0;
+#ifdef NO_snprintf
+#  ifdef HAS_sprintf_void
+    sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
+            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    for (len = 0; len < size; len++)
+        if (state->in[len] == 0) break;
+#  else
+    len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#else
+#  ifdef HAS_snprintf_void
+    snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    len = strlen(state->in);
+#  else
+    len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#endif
+
+    /* check that printf() results fit in buffer */
+    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+        return 0;
+
+    /* update buffer and position, defer compression until needed */
+    strm->avail_in = (unsigned)len;
+    strm->next_in = state->in;
+    state->pos += len;
+    return len;
+}
+
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzflush(file, flush)
+    gzFile file;
+    int flush;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* check flush parameter */
+    if (flush < 0 || flush > Z_FINISH)
+        return Z_STREAM_ERROR;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* compress remaining data with requested flush */
+    gz_comp(state, flush);
+    return state->err;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzsetparams(file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* if no change is requested, then do nothing */
+    if (level == state->level && strategy == state->strategy)
+        return Z_OK;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* change compression parameters for subsequent input */
+    if (state->size) {
+        /* flush previous input with previous parameters before changing */
+        if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
+            return state->err;
+        deflateParams(strm, level, strategy);
+    }
+    state->level = level;
+    state->strategy = strategy;
+    return Z_OK;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_w(file)
+    gzFile file;
+{
+    int ret = 0;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    /* check that we're writing */
+    if (state->mode != GZ_WRITE)
+        return Z_STREAM_ERROR;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        ret += gz_zero(state, state->skip);
+    }
+
+    /* flush, free memory, and close file */
+    ret += gz_comp(state, Z_FINISH);
+    (void)deflateEnd(&(state->strm));
+    free(state->out);
+    free(state->in);
+    gz_error(state, Z_OK, NULL);
+    free(state->path);
+    ret += close(state->fd);
+    free(state);
+    return ret ? Z_ERRNO : Z_OK;
+}
Index: deps/glpk/src/zlib/infback.c
===================================================================
--- deps/glpk/src/zlib/infback.c	(revision 9)
+++ deps/glpk/src/zlib/infback.c	(revision 9)
@@ -0,0 +1,632 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+   This code is largely copied from inflate.c.  Normally either infback.o or
+   inflate.o would be linked into an application--not both.  The interface
+   with inffast.c is retained so that optimized assembler-coded versions of
+   inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+   strm provides memory allocation functions in zalloc and zfree, or
+   Z_NULL to use the library memory allocation functions.
+
+   windowBits is in the range 8..15, and window is a user-supplied
+   window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL || window == Z_NULL ||
+        windowBits < 8 || windowBits > 15)
+        return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+                                               sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->dmax = 32768U;
+    state->wbits = windowBits;
+    state->wsize = 1U << windowBits;
+    state->window = window;
+    state->wnext = 0;
+    state->whave = 0;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Assure that some input is available.  If input is requested, but denied,
+   then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+    do { \
+        if (have == 0) { \
+            have = in(in_desc, &next); \
+            if (have == 0) { \
+                next = Z_NULL; \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+   with an error if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        PULL(); \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflateBack() with
+   an error. */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Assure that some output space is available, by writing out the window
+   if it's full.  If the write fails, return from inflateBack() with a
+   Z_BUF_ERROR. */
+#define ROOM() \
+    do { \
+        if (left == 0) { \
+            put = state->window; \
+            left = state->wsize; \
+            state->whave = left; \
+            if (out(out_desc, put, left)) { \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/*
+   strm provides the memory allocation functions and window buffer on input,
+   and provides information on the unused input on return.  For Z_DATA_ERROR
+   returns, strm will also provide an error message.
+
+   in() and out() are the call-back input and output functions.  When
+   inflateBack() needs more input, it calls in().  When inflateBack() has
+   filled the window with output, or when it completes with data in the
+   window, it calls out() to write out the data.  The application must not
+   change the provided input until in() is called again or inflateBack()
+   returns.  The application must not change the window/output buffer until
+   inflateBack() returns.
+
+   in() and out() are called with a descriptor parameter provided in the
+   inflateBack() call.  This parameter can be a structure that provides the
+   information required to do the read or write, as well as accumulated
+   information on the input and output such as totals and check values.
+
+   in() should return zero on failure.  out() should return non-zero on
+   failure.  If either in() or out() fails, than inflateBack() returns a
+   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
+   was in() or out() that caused in the error.  Otherwise,  inflateBack()
+   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+   error, or Z_MEM_ERROR if it could not allocate memory for the state.
+   inflateBack() can also return Z_STREAM_ERROR if the input parameters
+   are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code here;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Check that the strm exists and that the state was initialized */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* Reset the state */
+    strm->msg = Z_NULL;
+    state->mode = TYPE;
+    state->last = 0;
+    state->whave = 0;
+    next = strm->next_in;
+    have = next != Z_NULL ? strm->avail_in : 0;
+    hold = 0;
+    bits = 0;
+    put = state->window;
+    left = state->wsize;
+
+    /* Inflate until end of block marked as last */
+    for (;;)
+        switch (state->mode) {
+        case TYPE:
+            /* determine and dispatch block type */
+            if (state->last) {
+                BYTEBITS();
+                state->mode = DONE;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+
+        case STORED:
+            /* get and verify stored block length */
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+
+            /* copy stored block from input to output */
+            while (state->length != 0) {
+                copy = state->length;
+                PULL();
+                ROOM();
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+
+        case TABLE:
+            /* get dynamic table entries descriptor */
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+
+            /* get code length code lengths (not a typo) */
+            state->have = 0;
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+
+            /* get length and distance code code lengths */
+            state->have = 0;
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    here = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (here.val < 16) {
+                    NEEDBITS(here.bits);
+                    DROPBITS(here.bits);
+                    state->lens[state->have++] = here.val;
+                }
+                else {
+                    if (here.val == 16) {
+                        NEEDBITS(here.bits + 2);
+                        DROPBITS(here.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = (unsigned)(state->lens[state->have - 1]);
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (here.val == 17) {
+                        NEEDBITS(here.bits + 3);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(here.bits + 7);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* check for end-of-block code (better have one) */
+            if (state->lens[256] == 0) {
+                strm->msg = (char *)"invalid code -- missing end-of-block";
+                state->mode = BAD;
+                break;
+            }
+
+            /* build code tables -- note: do not change the lenbits or distbits
+               values here (9 and 6) without reading the comments in inftrees.h
+               concerning the ENOUGH constants, which depend on those values */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+
+        case LEN:
+            /* use inflate_fast() if we have enough input and output */
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                if (state->whave < state->wsize)
+                    state->whave = state->wsize - left;
+                inflate_fast(strm, state->wsize);
+                LOAD();
+                break;
+            }
+
+            /* get a literal, length, or end-of-block code */
+            for (;;) {
+                here = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (here.op && (here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(here.bits);
+            state->length = (unsigned)here.val;
+
+            /* process literal */
+            if (here.op == 0) {
+                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", here.val));
+                ROOM();
+                *put++ = (unsigned char)(state->length);
+                left--;
+                state->mode = LEN;
+                break;
+            }
+
+            /* process end of block */
+            if (here.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+
+            /* invalid code */
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+
+            /* length code -- get extra bits, if any */
+            state->extra = (unsigned)(here.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+
+            /* get distance code */
+            for (;;) {
+                here = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(here.bits);
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)here.val;
+
+            /* get distance extra bits, if any */
+            state->extra = (unsigned)(here.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            if (state->offset > state->wsize - (state->whave < state->wsize ?
+                                                left : 0)) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+
+            /* copy match from window to output */
+            do {
+                ROOM();
+                copy = state->wsize - state->offset;
+                if (copy < left) {
+                    from = put + copy;
+                    copy = left - copy;
+                }
+                else {
+                    from = put - state->offset;
+                    copy = left;
+                }
+                if (copy > state->length) copy = state->length;
+                state->length -= copy;
+                left -= copy;
+                do {
+                    *put++ = *from++;
+                } while (--copy);
+            } while (state->length != 0);
+            break;
+
+        case DONE:
+            /* inflate stream terminated properly -- write leftover output */
+            ret = Z_STREAM_END;
+            if (left < state->wsize) {
+                if (out(out_desc, state->window, state->wsize - left))
+                    ret = Z_BUF_ERROR;
+            }
+            goto inf_leave;
+
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+
+        default:                /* can't happen, but makes compilers happy */
+            ret = Z_STREAM_ERROR;
+            goto inf_leave;
+        }
+
+    /* Return unused input */
+  inf_leave:
+    strm->next_in = next;
+    strm->avail_in = have;
+    return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
Index: deps/glpk/src/zlib/inffast.c
===================================================================
--- deps/glpk/src/zlib/inffast.c	(revision 9)
+++ deps/glpk/src/zlib/inffast.c	(revision 9)
@@ -0,0 +1,340 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *in;      /* local strm->next_in */
+    unsigned char FAR *last;    /* while in < last, enough input available */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code here;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    wnext = state->wnext;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        here = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(here.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(here.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", here.val));
+            PUP(out) = (unsigned char)(here.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(here.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            here = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(here.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(here.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(here.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        if (state->sane) {
+                            strm->msg =
+                                (char *)"invalid distance too far back";
+                            state->mode = BAD;
+                            break;
+                        }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                        if (len <= op - whave) {
+                            do {
+                                PUP(out) = 0;
+                            } while (--len);
+                            continue;
+                        }
+                        len -= op - whave;
+                        do {
+                            PUP(out) = 0;
+                        } while (--op > whave);
+                        if (op == 0) {
+                            from = out - dist;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--len);
+                            continue;
+                        }
+#endif
+                    }
+                    from = window - OFF;
+                    if (wnext == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (wnext < op) {      /* wrap around window */
+                        from += wsize + wnext - op;
+                        op -= wnext;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (wnext < len) {  /* some from start of window */
+                                op = wnext;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += wnext - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                here = dcode[here.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            here = lcode[here.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and wnext == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
Index: deps/glpk/src/zlib/inffast.h
===================================================================
--- deps/glpk/src/zlib/inffast.h	(revision 9)
+++ deps/glpk/src/zlib/inffast.h	(revision 9)
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
Index: deps/glpk/src/zlib/inffixed.h
===================================================================
--- deps/glpk/src/zlib/inffixed.h	(revision 9)
+++ deps/glpk/src/zlib/inffixed.h	(revision 9)
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
Index: deps/glpk/src/zlib/inflate.c
===================================================================
--- deps/glpk/src/zlib/inflate.c	(revision 9)
+++ deps/glpk/src/zlib/inflate.c	(revision 9)
@@ -0,0 +1,1480 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+                              unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->wsize = 0;
+    state->whave = 0;
+    state->wnext = 0;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    state->sane = 1;
+    state->back = -1;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+    int wrap;
+    struct inflate_state FAR *state;
+
+    /* get the state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* extract wrap request from windowBits parameter */
+    if (windowBits < 0) {
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+        if (windowBits < 48)
+            windowBits &= 15;
+#endif
+    }
+
+    /* set number of window bits, free window if different */
+    if (windowBits && (windowBits < 8 || windowBits > 15))
+        return Z_STREAM_ERROR;
+    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+        ZFREE(strm, state->window);
+        state->window = Z_NULL;
+    }
+
+    /* update state and reset the rest of it */
+    state->wrap = wrap;
+    state->wbits = (unsigned)windowBits;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+    int ret;
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->window = Z_NULL;
+    ret = inflateReset2(strm, windowBits);
+    if (ret != Z_OK) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+    }
+    return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits < 0) {
+        state->hold = 0;
+        state->bits = 0;
+        return Z_OK;
+    }
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+               state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+    struct inflate_state FAR *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->wnext = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->wnext = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->wnext;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, strm->next_out - copy, copy);
+            state->wnext = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->wnext += dist;
+            if (state->wnext == state->wsize) state->wnext = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code here;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (state->wbits == 0)
+                state->wbits = len;
+            else if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if (state->flags & 0x0200) CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if (state->flags & 0x0200) CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if (state->flags & 0x0200)
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if (hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN_;             /* decode codes */
+                if (flush == Z_TREES) {
+                    DROPBITS(2);
+                    goto inf_leave;
+                }
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY_;
+            if (flush == Z_TREES) goto inf_leave;
+        case COPY_:
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    here = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (here.val < 16) {
+                    NEEDBITS(here.bits);
+                    DROPBITS(here.bits);
+                    state->lens[state->have++] = here.val;
+                }
+                else {
+                    if (here.val == 16) {
+                        NEEDBITS(here.bits + 2);
+                        DROPBITS(here.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (here.val == 17) {
+                        NEEDBITS(here.bits + 3);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(here.bits + 7);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* check for end-of-block code (better have one) */
+            if (state->lens[256] == 0) {
+                strm->msg = (char *)"invalid code -- missing end-of-block";
+                state->mode = BAD;
+                break;
+            }
+
+            /* build code tables -- note: do not change the lenbits or distbits
+               values here (9 and 6) without reading the comments in inftrees.h
+               concerning the ENOUGH constants, which depend on those values */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN_;
+            if (flush == Z_TREES) goto inf_leave;
+        case LEN_:
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                if (state->mode == TYPE)
+                    state->back = -1;
+                break;
+            }
+            state->back = 0;
+            for (;;) {
+                here = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (here.op && (here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            state->length = (unsigned)here.val;
+            if ((int)(here.op) == 0) {
+                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", here.val));
+                state->mode = LIT;
+                break;
+            }
+            if (here.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->back = -1;
+                state->mode = TYPE;
+                break;
+            }
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->was = state->length;
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                here = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)here.val;
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->whave) {
+                    if (state->sane) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                    Trace((stderr, "inflate.c too far\n"));
+                    copy -= state->whave;
+                    if (copy > state->length) copy = state->length;
+                    if (copy > left) copy = left;
+                    left -= copy;
+                    state->length -= copy;
+                    do {
+                        *put++ = 0;
+                    } while (--copy);
+                    if (state->length == 0) state->mode = LEN;
+                    break;
+#endif
+                }
+                if (copy > state->wnext) {
+                    copy -= state->wnext;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->wnext - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        if (updatewindow(strm, out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0) +
+                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+    struct inflate_state FAR *state;
+    unsigned long id;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id = adler32(0L, Z_NULL, 0);
+        id = adler32(id, dictionary, dictLength);
+        if (id != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    if (updatewindow(strm, strm->avail_out)) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    if (dictLength > state->wsize) {
+        zmemcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        zmemcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy(dest, source, sizeof(z_stream));
+    zmemcpy(copy, state, sizeof(struct inflate_state));
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+    return Z_OK;
+#else
+    state->sane = 1;
+    return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
+    state = (struct inflate_state FAR *)strm->state;
+    return ((long)(state->back) << 16) +
+        (state->mode == COPY ? state->length :
+            (state->mode == MATCH ? state->was - state->length : 0));
+}
Index: deps/glpk/src/zlib/inflate.h
===================================================================
--- deps/glpk/src/zlib/inflate.h	(revision 9)
+++ deps/glpk/src/zlib/inflate.h	(revision 9)
@@ -0,0 +1,122 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY_,      /* i/o: same as COPY below, but only first time in */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN_,       /* i: same as LEN below, but only first time in */
+            LEN,        /* i: waiting for length/lit/eob code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib) or (raw)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+                  HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+        (raw) -> TYPEDO
+    Read deflate blocks:
+            TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+            STORED -> COPY_ -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN_
+            LEN_ -> LEN
+    Read deflate codes in fixed or dynamic block:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 10K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+    int sane;                   /* if false, allow invalid distance too far */
+    int back;                   /* bits back of last unprocessed length/lit */
+    unsigned was;               /* initial length of match */
+};
Index: deps/glpk/src/zlib/inftrees.c
===================================================================
--- deps/glpk/src/zlib/inftrees.c	(revision 9)
+++ deps/glpk/src/zlib/inftrees.c	(revision 9)
@@ -0,0 +1,330 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.5 Copyright 1995-2010 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code here;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        here.op = (unsigned char)64;    /* invalid code marker */
+        here.bits = (unsigned char)1;
+        here.val = (unsigned short)0;
+        *(*table)++ = here;             /* make a table to force an error */
+        *(*table)++ = here;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min < max; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked for LENS and DIST tables against
+       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+       the initial root table size constants.  See the comments in inftrees.h
+       for more information.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if ((type == LENS && used >= ENOUGH_LENS) ||
+        (type == DISTS && used >= ENOUGH_DISTS))
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        here.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            here.op = (unsigned char)0;
+            here.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            here.op = (unsigned char)(extra[work[sym]]);
+            here.val = base[work[sym]];
+        }
+        else {
+            here.op = (unsigned char)(32 + 64);         /* end of block */
+            here.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = here;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if ((type == LENS && used >= ENOUGH_LENS) ||
+                (type == DISTS && used >= ENOUGH_DISTS))
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    here.op = (unsigned char)64;                /* invalid code marker */
+    here.bits = (unsigned char)(len - drop);
+    here.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            here.bits = (unsigned char)len;
+        }
+
+        /* put invalid code marker in table */
+        next[huff >> drop] = here;
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
Index: deps/glpk/src/zlib/inftrees.h
===================================================================
--- deps/glpk/src/zlib/inftrees.h	(revision 9)
+++ deps/glpk/src/zlib/inftrees.h	(revision 9)
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table.  The maximum number of code structures is
+   1444, which is the sum of 852 for literal/length codes and 592 for distance
+   codes.  These values were found by exhaustive searches using the program
+   examples/enough.c found in the zlib distribtution.  The arguments to that
+   program are the number of symbols, the initial root table size, and the
+   maximum bit length of a code.  "enough 286 9 15" for literal/length codes
+   returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+   The initial root table size (9 or 6) is found in the fifth argument of the
+   inflate_table() calls in inflate.c and infback.c.  If the root table size is
+   changed, then these maximum sizes would be need to be recalculated and
+   updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
Index: deps/glpk/src/zlib/trees.c
===================================================================
--- deps/glpk/src/zlib/trees.c	(revision 9)
+++ deps/glpk/src/zlib/trees.c	(revision 9)
@@ -0,0 +1,1244 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local int  detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (ush)val << s->bi_valid;\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (ush)(value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header,
+        "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+last, 3);    /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (s->strm->data_type == Z_UNKNOWN)
+            s->strm->data_type = detect_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+last, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+last, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (last) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ *    a) There are no non-portable control characters belonging to the
+ *       "black list" (0..6, 14..25, 28..31).
+ *    b) There is at least one printable character belonging to the
+ *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ *   "gray list" that is ignored in this detection algorithm:
+ *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+    deflate_state *s;
+{
+    /* black_mask is the bit mask of black-listed bytes
+     * set bits 0..6, 14..25, and 28..31
+     * 0xf3ffc07f = binary 11110011111111111100000001111111
+     */
+    unsigned long black_mask = 0xf3ffc07fUL;
+    int n;
+
+    /* Check for non-textual ("black-listed") bytes. */
+    for (n = 0; n <= 31; n++, black_mask >>= 1)
+        if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+            return Z_BINARY;
+
+    /* Check for textual ("white-listed") bytes. */
+    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+            || s->dyn_ltree[13].Freq != 0)
+        return Z_TEXT;
+    for (n = 32; n < LITERALS; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            return Z_TEXT;
+
+    /* There are no "black-listed" or "white-listed" bytes:
+     * this stream either is empty or has tolerated ("gray-listed") bytes only.
+     */
+    return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
Index: deps/glpk/src/zlib/trees.h
===================================================================
--- deps/glpk/src/zlib/trees.h	(revision 9)
+++ deps/glpk/src/zlib/trees.h	(revision 9)
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
+
Index: deps/glpk/src/zlib/uncompr.c
===================================================================
--- deps/glpk/src/zlib/uncompr.c	(revision 9)
+++ deps/glpk/src/zlib/uncompr.c	(revision 9)
@@ -0,0 +1,59 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+            return Z_DATA_ERROR;
+        return err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
Index: deps/glpk/src/zlib/zconf.h
===================================================================
--- deps/glpk/src/zlib/zconf.h	(revision 9)
+++ deps/glpk/src/zlib/zconf.h	(revision 9)
@@ -0,0 +1,168 @@
+/* zconf.h (configuration of the zlib compression library) */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, April 2011 */
+
+/* Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h. */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/* (file adler32.c) */
+#define adler32               _glp_zlib_adler32
+#define adler32_combine       _glp_zlib_adler32_combine
+#define adler32_combine64     _glp_zlib_adler32_combine64
+
+/* (file compress.c) */
+#define compress2             _glp_zlib_compress2
+#define compress              _glp_zlib_compress
+#define compressBound         _glp_zlib_compressBound
+
+/* (file crc32.c) */
+#define get_crc_table         _glp_zlib_get_crc_table
+#define crc32                 _glp_zlib_crc32
+#define crc32_combine         _glp_zlib_crc32_combine
+#define crc32_combine64       _glp_zlib_crc32_combine64
+
+/* (file deflate.c) */
+#define deflateInit_          _glp_zlib_deflateInit_
+#define deflateInit2_         _glp_zlib_deflateInit2_
+#define deflateSetDictionary  _glp_zlib_deflateSetDictionary
+#define deflateReset          _glp_zlib_deflateReset
+#define deflateSetHeader      _glp_zlib_deflateSetHeader
+#define deflatePrime          _glp_zlib_deflatePrime
+#define deflateParams         _glp_zlib_deflateParams
+#define deflateTune           _glp_zlib_deflateTune
+#define deflateBound          _glp_zlib_deflateBound
+#define deflate               _glp_zlib_deflate
+#define deflateEnd            _glp_zlib_deflateEnd
+#define deflateCopy           _glp_zlib_deflateCopy
+#define deflate_copyright     _glp_zlib_deflate_copyright
+
+/* (file gzclose.c) */
+#define gzclose               _glp_zlib_gzclose
+
+/* (file gzlib.c) */
+#define gzopen                _glp_zlib_gzopen
+#define gzopen64              _glp_zlib_gzopen64
+#define gzdopen               _glp_zlib_gzdopen
+#define gzbuffer              _glp_zlib_gzbuffer
+#define gzrewind              _glp_zlib_gzrewind
+#define gzseek64              _glp_zlib_gzseek64
+#define gzseek                _glp_zlib_gzseek
+#define gztell64              _glp_zlib_gztell64
+#define gztell                _glp_zlib_gztell
+#define gzoffset64            _glp_zlib_gzoffset64
+#define gzoffset              _glp_zlib_gzoffset
+#define gzeof                 _glp_zlib_gzeof
+#define gzerror               _glp_zlib_gzerror
+#define gzclearerr            _glp_zlib_gzclearerr
+#define gz_error              _glp_zlib_gz_error
+
+/* (file gzread.c) */
+#define gzread                _glp_zlib_gzread
+#define gzgetc                _glp_zlib_gzgetc
+#define gzungetc              _glp_zlib_gzungetc
+#define gzgets                _glp_zlib_gzgets
+#define gzdirect              _glp_zlib_gzdirect
+#define gzclose_r             _glp_zlib_gzclose_r
+
+/* (file gzwrite.c) */
+#define gzwrite               _glp_zlib_gzwrite
+#define gzputc                _glp_zlib_gzputc
+#define gzputs                _glp_zlib_gzputs
+#define gzprintf              _glp_zlib_gzprintf
+#define gzflush               _glp_zlib_gzflush
+#define gzsetparams           _glp_zlib_gzsetparams
+#define gzclose_w             _glp_zlib_gzclose_w
+
+/* (file infback.c) */
+#define inflateBackInit_      _glp_zlib_inflateBackInit_
+#define inflateBack           _glp_zlib_inflateBack
+#define inflateBackEnd        _glp_zlib_inflateBackEnd
+
+/* (file inffast.c) */
+#define inflate_fast          _glp_zlib_inflate_fast
+
+/* (file inflate.c) */
+#define inflateReset          _glp_zlib_inflateReset
+#define inflateReset2         _glp_zlib_inflateReset2
+#define inflateInit2_         _glp_zlib_inflateInit2_
+#define inflateInit_          _glp_zlib_inflateInit_
+#define inflatePrime          _glp_zlib_inflatePrime
+#define inflate               _glp_zlib_inflate
+#define inflateEnd            _glp_zlib_inflateEnd
+#define inflateSetDictionary  _glp_zlib_inflateSetDictionary
+#define inflateGetHeader      _glp_zlib_inflateGetHeader
+#define inflateSync           _glp_zlib_inflateSync
+#define inflateSyncPoint      _glp_zlib_inflateSyncPoint
+#define inflateCopy           _glp_zlib_inflateCopy
+#define inflateUndermine      _glp_zlib_inflateUndermine
+#define inflateMark           _glp_zlib_inflateMark
+
+/* (file inftrees.c) */
+#define inflate_table         _glp_zlib_inflate_table
+#define inflate_copyright     _glp_zlib_inflate_copyright
+
+/* (file trees.c) */
+#define _tr_init              _glp_zlib_tr_init
+#define _tr_stored_block      _glp_zlib_tr_stored_block
+#define _tr_align             _glp_zlib_tr_align
+#define _tr_flush_block       _glp_zlib_tr_flush_block
+#define _tr_tally             _glp_zlib_tr_tally
+#define _dist_code            _glp_zlib_dist_code
+#define _length_code          _glp_zlib_length_code
+
+/* (file uncompr.c) */
+#define uncompress            _glp_zlib_uncompress
+
+/* (file zutil.c) */
+#define zlibVersion           _glp_zlib_zlibVersion
+#define zlibCompileFlags      _glp_zlib_zlibCompileFlags
+#define zError                _glp_zlib_zError
+#define zcalloc               _glp_zlib_zcalloc
+#define zcfree                _glp_zlib_zcfree
+#define z_errmsg              _glp_zlib_z_errmsg
+
+#define STDC 1
+
+#define MAX_MEM_LEVEL 9
+
+#define MAX_WBITS 15
+
+#define OF(args) args
+
+#define ZEXTERN extern
+#define ZEXPORT
+#define ZEXPORTVA
+
+#define FAR
+
+typedef unsigned char Byte;
+typedef unsigned int uInt;
+typedef unsigned long uLong;
+
+typedef Byte Bytef;
+typedef char charf;
+typedef int intf;
+typedef uInt uIntf;
+typedef uLong uLongf;
+
+typedef void const *voidpc;
+typedef void *voidpf;
+typedef void *voidp;
+
+#define z_off_t long
+
+#define z_off64_t z_off_t
+
+#define NO_vsnprintf 1
+
+#endif
+
+/* eof */
Index: deps/glpk/src/zlib/zio.c
===================================================================
--- deps/glpk/src/zlib/zio.c	(revision 9)
+++ deps/glpk/src/zlib/zio.c	(revision 9)
@@ -0,0 +1,92 @@
+/* zio.c (simulation of non-standard low-level i/o functions) */
+
+/* Written by Andrew Makhorin <mao@gnu.org>, April 2011
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* (reserved for copyright notice) */
+
+#include <assert.h>
+#include <stdio.h>
+#include "zio.h"
+
+static FILE *file[FOPEN_MAX];
+static int initialized = 0;
+
+static void initialize(void)
+{     int fd;
+      assert(!initialized);
+      file[0] = stdin;
+      file[1] = stdout;
+      file[2] = stderr;
+      for (fd = 3; fd < FOPEN_MAX; fd++)
+         file[fd] = NULL;
+      initialized = 1;
+      return;
+}
+
+int open(const char *path, int oflag, ...)
+{     FILE *fp;
+      int fd;
+      if (!initialized) initialize();
+      /* see file gzlib.c, function gz_open */
+      if (oflag == O_RDONLY)
+         fp = fopen(path, "rb");
+      else if (oflag == (O_WRONLY | O_CREAT | O_TRUNC))
+         fp = fopen(path, "wb");
+      else if (oflag == (O_WRONLY | O_CREAT | O_APPEND))
+         fp = fopen(path, "ab");
+      else
+         assert(oflag != oflag);
+      if (fp == NULL)
+         return -1;
+      for (fd = 0; fd < FOPEN_MAX; fd++)
+         if (file[fd] == NULL) break;
+      assert(fd < FOPEN_MAX);
+      file[fd] = fp;
+      return fd;
+}
+
+long read(int fd, void *buf, unsigned long nbyte)
+{     unsigned long count;
+      if (!initialized) initialize();
+      assert(0 <= fd && fd < FOPEN_MAX);
+      assert(file[fd] != NULL);
+      count = fread(buf, 1, nbyte, file[fd]);
+      if (ferror(file[fd]))
+         return -1;
+      return count;
+}
+
+long write(int fd, const void *buf, unsigned long nbyte)
+{     unsigned long count;
+      if (!initialized) initialize();
+      assert(0 <= fd && fd < FOPEN_MAX);
+      assert(file[fd] != NULL);
+      count = fwrite(buf, 1, nbyte, file[fd]);
+      if (count != nbyte)
+         return -1;
+      if (fflush(file[fd]) != 0)
+         return -1;
+      return count;
+}
+
+long lseek(int fd, long offset, int whence)
+{     if (!initialized) initialize();
+      assert(0 <= fd && fd < FOPEN_MAX);
+      assert(file[fd] != NULL);
+      if (fseek(file[fd], offset, whence) != 0)
+         return -1;
+      return ftell(file[fd]);
+}
+
+int close(int fd)
+{     if (!initialized) initialize();
+      assert(0 <= fd && fd < FOPEN_MAX);
+      assert(file[fd] != NULL);
+      fclose(file[fd]);
+      file[fd] = NULL;
+      return 0;
+}
+
+/* eof */
Index: deps/glpk/src/zlib/zio.h
===================================================================
--- deps/glpk/src/zlib/zio.h	(revision 9)
+++ deps/glpk/src/zlib/zio.h	(revision 9)
@@ -0,0 +1,37 @@
+/* zio.h (simulation of non-standard low-level i/o functions) */
+
+/* Written by Andrew Makhorin <mao@gnu.org>, April 2011
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h. */
+
+#ifndef ZIO_H
+#define ZIO_H
+
+#define O_RDONLY 0x00
+#define O_WRONLY 0x01
+#define O_CREAT  0x10
+#define O_TRUNC  0x20
+#define O_APPEND 0x30
+
+#define open _glp_zlib_open
+int open(const char *path, int oflag, ...);
+
+#define read _glp_zlib_read
+long read(int fd, void *buf, unsigned long nbyte);
+
+#define write _glp_zlib_write
+long write(int fd, const void *buf, unsigned long nbyte);
+
+#define lseek _glp_zlib_lseek
+long lseek(int fd, long offset, int whence);
+
+#define close _glp_zlib_close
+int close(int fd);
+
+#endif
+
+/* eof */
Index: deps/glpk/src/zlib/zlib.h
===================================================================
--- deps/glpk/src/zlib/zlib.h	(revision 9)
+++ deps/glpk/src/zlib/zlib.h	(revision 9)
@@ -0,0 +1,1613 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.5, April 19th, 2010
+
+  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.5"
+#define ZLIB_VERNUM 0x1250
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 5
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+    The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed data.
+  This version of the library supports only one compression method (deflation)
+  but other algorithms will be added later and will have the same stream
+  interface.
+
+    Compression can be done in a single step if the buffers are large enough,
+  or can be done by repeated calls of the compression function.  In the latter
+  case, the application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+    The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+    The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+    This library can optionally read and write gzip streams in memory as well.
+
+    The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+    The library does not install any signal handler.  The decoder checks
+  the consistency of the compressed data, so the library should never crash
+  even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+     The application must update next_in and avail_in when avail_in has dropped
+   to zero.  It must update next_out and avail_out when avail_out has dropped
+   to zero.  The application must initialize zalloc, zfree and opaque before
+   calling the init function.  All other fields are set by the compression
+   library and must not be updated by the application.
+
+     The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree.  This can be useful for custom
+   memory management.  The compression library attaches no meaning to the
+   opaque value.
+
+     zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+     On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this if
+   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
+   returned by zalloc for objects of exactly 65536 bytes *must* have their
+   offset normalized to zero.  The default allocation function provided by this
+   library ensures this (see zutil.c).  To reduce memory requirements and avoid
+   any allocation of 64K objects, at the expense of compression ratio, compile
+   the library with -DMAX_WBITS=14 (see zconf.h).
+
+     The fields total_in and total_out can be used for statistics or progress
+   reports.  After compression, total_in holds the total size of the
+   uncompressed data and may be saved for use in the decompressor (particularly
+   if the decompressor wants to decompress everything in a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+#define Z_TREES         6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at all
+   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
+   requests a default compromise between speed and compression (currently
+   equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if level is not a valid compression level, or
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
+   if there is no error message.  deflateInit does not perform any compression:
+   this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).  Some
+    output may be provided even if flush is not set.
+
+    Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating avail_in or avail_out accordingly; avail_out should
+  never be zero before the call.  The application can consume the compressed
+  output when it wants, for example when the output buffer is full (avail_out
+  == 0), or after each call of deflate().  If deflate returns Z_OK and with
+  zero avail_out, it must be called again after making room in the output
+  buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumulate before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far.  (In
+  particular avail_in is zero after the call if enough output space has been
+  provided before the call.) Flushing may degrade compression for some
+  compression algorithms and so it should be used only when necessary.  This
+  completes the current deflate block and follows it with an empty stored block
+  that is three bits plus filler bits to the next byte, followed by four bytes
+  (00 00 ff ff).
+
+    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+  output buffer, but the output is not aligned to a byte boundary.  All of the
+  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+  This completes the current deflate block and follows it with an empty fixed
+  codes block that is 10 bits long.  This assures that enough bytes are output
+  in order for the decompressor to finish the block before the empty fixed code
+  block.
+
+    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+  seven bits of the current block are held to be written as the next byte after
+  the next deflate block is completed.  In this case, the decompressor may not
+  be provided enough bits at this point in order to complete decompression of
+  the data provided so far to the compressor.  It may need to wait for the next
+  block to be emitted.  This is for advanced applications that need to control
+  the emission of deflate blocks.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there was
+  enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error.  After
+  deflate has returned Z_STREAM_END, the only possible operations on the stream
+  are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step.  In this case, avail_out must be at least the
+  value returned by deflateBound (see below).  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
+  binary.  This field is only for information purposes and does not affect the
+  compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
+   exact value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit() does not process any header information -- that is deferred
+   until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing will
+    resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there is
+    no more input data or no more space in the output buffer (see below about
+    the flush parameter).
+
+    Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating the next_* and avail_* values accordingly.  The
+  application can consume the uncompressed output when it wants, for example
+  when the output buffer is full (avail_out == 0), or after each call of
+  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
+  called again after making room in the output buffer because there might be
+  more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer.  Z_BLOCK requests that inflate()
+  stop if and when it gets to the next deflate block boundary.  When decoding
+  the zlib or gzip format, this will cause inflate() to return immediately
+  after the header and before the first block.  When doing a raw inflate,
+  inflate() will go ahead and process the first block, and will return when it
+  gets to the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64 if
+  inflate() is currently decoding the last block in the deflate stream, plus
+  128 if inflate() returned immediately after decoding an end-of-block code or
+  decoding the complete header up to just before the first byte of the deflate
+  stream.  The end-of-block will not be indicated until all of the uncompressed
+  data from that block has been written to strm->next_out.  The number of
+  unused bits may in general be greater than seven, except when bit 7 of
+  data_type is set, in which case the number of unused bits will be less than
+  eight.  data_type is set as noted here every time inflate() returns for all
+  flush options, and so can be used to determine the amount of currently
+  consumed input in bits.
+
+    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+  end of each deflate block header is reached, before any actual data in that
+  block is decoded.  This allows the caller to determine the length of the
+  deflate block header for later use in random access within a deflate block.
+  256 is added to the value of strm->data_type when inflate() returns
+  immediately after reaching the end of the deflate block header.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error.  However if all decompression is to be performed in a single step (a
+  single call of inflate), the parameter flush should be set to Z_FINISH.  In
+  this case all pending input is processed and all pending output is flushed;
+  avail_out must be large enough to hold all the uncompressed data.  (The size
+  of the uncompressed data may have been saved by the compressor for this
+  purpose.) The next operation on this stream must be inflateEnd to deallocate
+  the decompression state.  The use of Z_FINISH is never required, but can be
+  used to inform inflate that a faster approach may be used for the single
+  inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call.  So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK or Z_TREES is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below.  At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically, if requested when
+  initializing with inflateInit2().  Any information contained in the gzip
+  header is not retained, so applications that need that information should
+  instead use raw inflate, see inflateInit2() below, or inflateBack() and
+  perform their own processing of the gzip header and trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing.  If Z_DATA_ERROR is returned, the application may
+  then call inflateSync() to look for a good compression block if a partial
+  recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent.  In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, zalloc, zfree and opaque must be initialized before by the
+   caller.
+
+     The method parameter is the compression method.  It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library.  Larger values of this parameter result in better
+   compression at the expense of memory usage.  The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
+   determines the window size.  deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding.  Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper.  The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero), no
+   header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state.  memLevel=1 uses minimum memory but is
+   slow and reduces compression ratio; memLevel=9 uses maximum memory for
+   optimal speed.  The default value is 8.  See zconf.h for total memory usage
+   as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm.  Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding).  Filtered data consists mostly of small values with a somewhat
+   random distribution.  In this case, the compression algorithm is tuned to
+   compress them better.  The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
+   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
+   strategy parameter only affects the compression ratio but not the
+   correctness of the compressed output even if it is not set appropriately.
+   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+   decoder for special applications.
+
+     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
+   set to null if there is no error message.  deflateInit2 does not perform any
+   compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any call
+   of deflate.  The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort).  deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.  The
+   stream will keep the same compression level and any other attributes that
+   may have been set by deflateInit2.
+
+     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression level is changed, the input available so far is
+   compressed with the old level (and may be flushed); the new level will take
+   effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to be
+   compressed and flushed.  In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+   strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is.  Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding.  Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
+   crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit2 does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit2() does not process any header information -- that is
+   deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+     Skips invalid compressed data until a full flush point (see above the
+   description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+   if no more input was provided, Z_DATA_ERROR if no flush point has been
+   found, or Z_STREAM_ERROR if the stream structure was inconsistent.  In the
+   success case, the application may save the current current value of total_in
+   which indicates where valid compressed data was found.  In the error case,
+   the application may repeatedly call inflateSync, providing more input each
+   time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.  The
+   stream will keep attributes that may have been set by inflateInit2.
+
+     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+                                      int windowBits));
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.
+
+     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+   the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above or -1 << 16 if the provided
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the normal
+   behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+   in the deflate stream (in which case strm->msg is set to indicate the nature
+   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+   In the case of Z_BUF_ERROR, an input or output error can be distinguished
+   using strm->next_in which will be Z_NULL only if in() returned an error.  If
+   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+   non-zero.  (in() will always be called before out(), so strm->next_in is
+   assured to be defined if out() returns non-zero.) Note that inflateBack()
+   cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be large enough to hold the entire
+   uncompressed data.  (The size of the uncompressed data must have been saved
+   previously by the compressor and transmitted to the decompressor by some
+   mechanism outside the scope of this compression library.) Upon exit, destLen
+   is the actual size of the uncompressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+                        /* gzip file access functions */
+
+/*
+     This library supports reading and writing files in gzip (.gz) format with
+   an interface similar to that of stdio, using the functions that start with
+   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
+   wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef voidp gzFile;       /* opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
+   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+   for fixed code compression as in "wb9F".  (See the description of
+   deflateInit2 for more information about the strategy parameter.) Also "a"
+   can be used instead of "w" to request that the gzip stream that will be
+   written be appended to the file.  "+" will result in an error, since reading
+   and writing to the same gzip file is not supported.
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened, if there was
+   insufficient memory to allocate the gzFile state, or if an invalid mode was
+   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+   errno can be checked to determine if the reason gzopen failed was that the
+   file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
+   are obtained from calls like open, dup, creat, pipe or fileno (if the file
+   has been previously opened with fopen).  The mode parameter is as in gzopen.
+
+     The next call of gzclose on the returned gzFile will also close the file
+   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+   mode);.  The duplicated descriptor should be saved to avoid a leak, since
+   gzdopen does not close fd if it fails.
+
+     gzdopen returns NULL if there was insufficient memory to allocate the
+   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
+   used until the next gz* read, write, seek, or close operation, so gzdopen
+   will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+     Set the internal buffer size used by this library's functions.  The
+   default buffer size is 8192 bytes.  This function must be called after
+   gzopen() or gzdopen(), and before any other calls that read or write the
+   file.  The buffer memory allocation is always deferred to the first read or
+   write.  Two buffers are allocated, either both of the specified size when
+   writing, or one of the specified size and the other twice that size when
+   reading.  A larger buffer size of, for example, 64K or 128K bytes will
+   noticeably increase the speed of decompression (reading).
+
+     The new buffer size also affects the maximum length for gzprintf().
+
+     gzbuffer() returns 0 on success, or -1 on failure, such as being called
+   too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.
+
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  If
+   the input file was not in gzip format, gzread copies the given number of
+   bytes into the buffer.
+
+     After reaching the end of a gzip stream in the input, gzread will continue
+   to read, looking for another gzip stream, or failing that, reading the rest
+   of the input file directly without decompression.  The entire input file
+   will be read if gzread is called until it returns less than the requested
+   len.
+
+     gzread returns the number of uncompressed bytes actually read, less than
+   len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+                                voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or 0 in case of error.  The number of
+   uncompressed bytes written is limited to 8191, or one less than the buffer
+   size given to gzbuffer().  The caller should assure that this limit is not
+   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
+   nothing written.  In this case, there may also be a buffer overflow with
+   unpredictable consequences, which is possible only if zlib was compiled with
+   the insecure functions sprintf() or vsprintf() because the secure snprintf()
+   or vsnprintf() functions were not available.  This can be determined using
+   zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or a
+   newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  If any characters are read or if len == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, then the buffer is left untouched.
+
+     gzgets returns buf which is a null-terminated string, or it returns NULL
+   for end-of-file or in case of error.  If there was an error, the contents at
+   buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+     Reads one byte from the compressed file.  gzgetc returns this byte or -1
+   in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is allowed.
+   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
+   fail if c is -1, and may fail if a character has been pushed but not read
+   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
+   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
+   The pushed character will be discarded if the stream is repositioned with
+   gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file.  The parameter flush
+   is as in the deflate() function.  The return value is the zlib error number
+   (see function gzerror below).  gzflush is only permitted when writing.
+
+     If the flush parameter is Z_FINISH, the remaining data is written and the
+   gzip stream is completed in the output.  If gzwrite() is called again, a new
+   gzip stream will be started in the output.  gzread() is able to read such
+   concatented gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+                                   z_off_t offset, int whence));
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed file.  The offset represents a number of bytes in the
+   uncompressed data stream.  The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow.  If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+     gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed file.  This position represents a number of bytes in the
+   uncompressed data stream, and is zero when starting, even if appending or
+   reading a gzip stream from the middle of a file using gzdopen().
+
+     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+     Returns the current offset in the file being read or written.  This offset
+   includes the count of bytes that precede the gzip stream, for example when
+   appending or when using gzdopen() for reading.  When reading, the offset
+   does not include as yet unused buffered input.  This information can be used
+   for a progress indicator.  On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns true (1) if the end-of-file indicator has been set while reading,
+   false (0) otherwise.  Note that the end-of-file indicator is set only if the
+   read tried to go past the end of the input, but came up short.  Therefore,
+   just like feof(), gzeof() may return false even if there is no more data to
+   read, in the event that the last read request was for the exact number of
+   bytes remaining in the input file.  This will happen if the input file size
+   is an exact multiple of the buffer size.
+
+     If gzeof() returns true, then the read functions will return no more data,
+   unless the end-of-file indicator is reset by gzclearerr() and the input file
+   has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns true (1) if file is being copied directly while reading, or false
+   (0) if file is a gzip stream being decompressed.  This state can change from
+   false to true while reading the input file if the end of a gzip stream is
+   reached, but is followed by data that is not another gzip stream.
+
+     If the input file is empty, gzdirect() will return true, since the input
+   does not contain a gzip stream.
+
+     If gzdirect() is used immediately after gzopen() or gzdopen() it will
+   cause buffers to be allocated to allow reading the file to determine if it
+   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
+   gzdirect().
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates the (de)compression state.  Note that once file is closed, you
+   cannot call gzerror with file, since its structures have been deallocated.
+   gzclose must not be called more than once on the same file, just as free
+   must not be called more than once on the same allocation.
+
+     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+   file operation error, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed file.  errnum is set to zlib error number.  If an error occurred
+   in the file system and not in the compression library, errnum is set to
+   Z_ERRNO and the application may consult errno to get the exact error code.
+
+     The application must not modify the returned string.  Future calls to
+   this function may invalidate the previously returned string.  If file is
+   closed, then the string previously returned by gzerror will no longer be
+   available.
+
+     gzerror() should be used to distinguish errors from end-of-file for those
+   functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file.  This is analogous to the
+   clearerr() function in stdio.  This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the compression
+   library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  If buf is Z_NULL, this function returns the
+   required initial value for the checksum.
+
+     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster.
+
+   Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  If buf is Z_NULL, this function returns the required
+   initial value for the for the crc.  Pre- and post-conditioning (one's
+   complement) is performed within this function so it shouldn't be done by the
+   application.
+
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+                                            ZLIB_VERSION, sizeof(z_stream))
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0
+#  define gzopen gzopen64
+#  define gzseek gzseek64
+#  define gztell gztell64
+#  define gzoffset gzoffset64
+#  define adler32_combine adler32_combine64
+#  define crc32_combine crc32_combine64
+#  ifdef _LARGEFILE64_SOURCE
+     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#  endif
+#else
+   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
Index: deps/glpk/src/zlib/zutil.c
===================================================================
--- deps/glpk/src/zlib/zutil.c	(revision 9)
+++ deps/glpk/src/zlib/zutil.c	(revision 9)
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch ((int)(sizeof(uInt))) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch ((int)(sizeof(uLong))) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch ((int)(sizeof(voidpf))) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch ((int)(sizeof(z_off_t))) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#ifdef STDC
+#  ifdef NO_vsnprintf
+        flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#else
+        flags += 1L << 24;
+#  ifdef NO_snprintf
+        flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
Index: deps/glpk/src/zlib/zutil.h
===================================================================
--- deps/glpk/src/zlib/zutil.h	(revision 9)
+++ deps/glpk/src/zlib/zutil.h	(revision 9)
@@ -0,0 +1,93 @@
+/* zutil.h (internal interface of the zlib compression library) */
+
+/* Modified by Andrew Makhorin <mao@gnu.org>, April 2011 */
+
+/* Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in
+ * zlib.h */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h. */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+
+#include "zlib.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define local static
+
+typedef unsigned char uch;
+typedef uch uchf;
+typedef unsigned short ush;
+typedef ush ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10];
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm, err) \
+      return (strm->msg = (char *)ERR_MSG(err), (err))
+
+#define DEF_WBITS MAX_WBITS
+
+#if MAX_MEM_LEVEL >= 8
+#define DEF_MEM_LEVEL 8
+#else
+#define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+
+#define PRESET_DICT 0x20
+
+#define OS_CODE 0x03 /* assume Unix */
+
+#define HAVE_MEMCPY 1
+#define zmemcpy memcpy
+#define zmemzero(dest, len) memset(dest, 0, len)
+
+#ifdef DEBUG
+#include <stdio.h>
+extern int ZLIB_INTERNAL z_verbose;
+extern void ZLIB_INTERNAL z_error OF((char *m));
+#define Assert(cond, msg) { if(!(cond)) z_error(msg); }
+#define Trace(x) { if (z_verbose >= 0) fprintf x; }
+#define Tracev(x) { if (z_verbose > 0) fprintf x; }
+#define Tracevv(x) {if (z_verbose > 1) fprintf x; }
+#define Tracec(c, x) {if (z_verbose > 0 && (c)) fprintf x; }
+#define Tracecv(c, x) {if (z_verbose > 1 && (c)) fprintf x; }
+#else
+#define Assert(cond, msg)
+#define Trace(x)
+#define Tracev(x)
+#define Tracevv(x)
+#define Tracec(c, x)
+#define Tracecv(c, x)
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+      unsigned size));
+void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+      (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) \
+      (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) { if (p) ZFREE(s, p); }
+
+#endif
+
+/* eof */
Index: deps/glpk/w32/Build_GLPK_with_VC10.bat
===================================================================
--- deps/glpk/w32/Build_GLPK_with_VC10.bat	(revision 9)
+++ deps/glpk/w32/Build_GLPK_with_VC10.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK with Microsoft Visual Studio Express 2010
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files\Microsoft Visual Studio 10.0\VC"
+
+call %HOME%\vcvarsall.bat x86
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC
+%HOME%\bin\nmake.exe /f Makefile_VC check
+
+pause
Index: deps/glpk/w32/Build_GLPK_with_VC10_DLL.bat
===================================================================
--- deps/glpk/w32/Build_GLPK_with_VC10_DLL.bat	(revision 9)
+++ deps/glpk/w32/Build_GLPK_with_VC10_DLL.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK DLL with Microsoft Visual Studio Express 2010
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files\Microsoft Visual Studio 10.0\VC"
+
+call %HOME%\vcvarsall.bat x86
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
+
+pause
Index: deps/glpk/w32/Build_GLPK_with_VC9.bat
===================================================================
--- deps/glpk/w32/Build_GLPK_with_VC9.bat	(revision 9)
+++ deps/glpk/w32/Build_GLPK_with_VC9.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK with Microsoft Visual Studio Express 2008
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files\Microsoft Visual Studio 9.0\VC"
+
+call %HOME%\bin\vcvars32.bat
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC
+%HOME%\bin\nmake.exe /f Makefile_VC check
+
+pause
Index: deps/glpk/w32/Build_GLPK_with_VC9_DLL.bat
===================================================================
--- deps/glpk/w32/Build_GLPK_with_VC9_DLL.bat	(revision 9)
+++ deps/glpk/w32/Build_GLPK_with_VC9_DLL.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK DLL with Microsoft Visual Studio Express 2008
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files\Microsoft Visual Studio 9.0\VC"
+
+call %HOME%\bin\vcvars32.bat
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
+
+pause
Index: deps/glpk/w32/Makefile_VC
===================================================================
--- deps/glpk/w32/Makefile_VC	(revision 9)
+++ deps/glpk/w32/Makefile_VC	(revision 9)
@@ -0,0 +1,168 @@
+## Build GLPK with Microsoft Visual Studio Express ##
+
+CFLAGS = \
+/I. \
+/I..\src \
+/I..\src\amd \
+/I..\src\colamd \
+/I..\src\minisat \
+/I..\src\zlib \
+/DHAVE_CONFIG_H=1 \
+/D_CRT_SECURE_NO_WARNINGS=1 \
+/nologo \
+/W3 \
+/O2
+
+OBJSET = \
+..\src\glpapi01.obj \
+..\src\glpapi02.obj \
+..\src\glpapi03.obj \
+..\src\glpapi04.obj \
+..\src\glpapi05.obj \
+..\src\glpapi06.obj \
+..\src\glpapi07.obj \
+..\src\glpapi08.obj \
+..\src\glpapi09.obj \
+..\src\glpapi10.obj \
+..\src\glpapi11.obj \
+..\src\glpapi12.obj \
+..\src\glpapi13.obj \
+..\src\glpapi14.obj \
+..\src\glpapi15.obj \
+..\src\glpapi16.obj \
+..\src\glpapi17.obj \
+..\src\glpapi18.obj \
+..\src\glpapi19.obj \
+..\src\glpapi20.obj \
+..\src\glpapi21.obj \
+..\src\glpavl.obj \
+..\src\glpbfd.obj \
+..\src\glpbfx.obj \
+..\src\glpcpx.obj \
+..\src\glpdmp.obj \
+..\src\glpdmx.obj \
+..\src\glpenv01.obj \
+..\src\glpenv02.obj \
+..\src\glpenv03.obj \
+..\src\glpenv04.obj \
+..\src\glpenv05.obj \
+..\src\glpenv06.obj \
+..\src\glpenv07.obj \
+..\src\glpenv08.obj \
+..\src\glpfhv.obj \
+..\src\glpgmp.obj \
+..\src\glphbm.obj \
+..\src\glpini01.obj \
+..\src\glpini02.obj \
+..\src\glpios01.obj \
+..\src\glpios02.obj \
+..\src\glpios03.obj \
+..\src\glpios04.obj \
+..\src\glpios05.obj \
+..\src\glpios06.obj \
+..\src\glpios07.obj \
+..\src\glpios08.obj \
+..\src\glpios09.obj \
+..\src\glpios10.obj \
+..\src\glpios11.obj \
+..\src\glpios12.obj \
+..\src\glpipm.obj \
+..\src\glplib01.obj \
+..\src\glplib02.obj \
+..\src\glplib03.obj \
+..\src\glplpf.obj \
+..\src\glplpx01.obj \
+..\src\glplpx02.obj \
+..\src\glplpx03.obj \
+..\src\glpluf.obj \
+..\src\glplux.obj \
+..\src\glpmat.obj \
+..\src\glpmpl01.obj \
+..\src\glpmpl02.obj \
+..\src\glpmpl03.obj \
+..\src\glpmpl04.obj \
+..\src\glpmpl05.obj \
+..\src\glpmpl06.obj \
+..\src\glpmps.obj \
+..\src\glpnet01.obj \
+..\src\glpnet02.obj \
+..\src\glpnet03.obj \
+..\src\glpnet04.obj \
+..\src\glpnet05.obj \
+..\src\glpnet06.obj \
+..\src\glpnet07.obj \
+..\src\glpnet08.obj \
+..\src\glpnet09.obj \
+..\src\glpnpp01.obj \
+..\src\glpnpp02.obj \
+..\src\glpnpp03.obj \
+..\src\glpnpp04.obj \
+..\src\glpnpp05.obj \
+..\src\glpnpp06.obj \
+..\src\glpqmd.obj \
+..\src\glprgr.obj \
+..\src\glprng01.obj \
+..\src\glprng02.obj \
+..\src\glpscf.obj \
+..\src\glpscl.obj \
+..\src\glpsdf.obj \
+..\src\glpspm.obj \
+..\src\glpspx01.obj \
+..\src\glpspx02.obj \
+..\src\glpsql.obj \
+..\src\glpssx01.obj \
+..\src\glpssx02.obj \
+..\src\glptsp.obj \
+..\src\amd\amd_1.obj \
+..\src\amd\amd_2.obj \
+..\src\amd\amd_aat.obj \
+..\src\amd\amd_control.obj \
+..\src\amd\amd_defaults.obj \
+..\src\amd\amd_dump.obj \
+..\src\amd\amd_info.obj \
+..\src\amd\amd_order.obj \
+..\src\amd\amd_post_tree.obj \
+..\src\amd\amd_postorder.obj \
+..\src\amd\amd_preprocess.obj \
+..\src\amd\amd_valid.obj \
+..\src\colamd\colamd.obj \
+..\src\minisat\minisat.obj \
+..\src\zlib\adler32.obj \
+..\src\zlib\compress.obj \
+..\src\zlib\crc32.obj \
+..\src\zlib\deflate.obj \
+..\src\zlib\gzclose.obj \
+..\src\zlib\gzlib.obj \
+..\src\zlib\gzread.obj \
+..\src\zlib\gzwrite.obj \
+..\src\zlib\infback.obj \
+..\src\zlib\inffast.obj \
+..\src\zlib\inflate.obj \
+..\src\zlib\inftrees.obj \
+..\src\zlib\trees.obj \
+..\src\zlib\uncompr.obj \
+..\src\zlib\zio.obj \
+..\src\zlib\zutil.obj
+
+.c.obj:
+        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
+
+all: glpk.lib glpsol.exe
+
+glpk.lib: $(OBJSET)
+        lib.exe /out:glpk.lib \
+                ..\src\*.obj \
+                ..\src\amd\*.obj \
+                ..\src\colamd\*.obj \
+                ..\src\minisat\*.obj \
+                ..\src\zlib\*.obj
+
+glpsol.exe: ..\examples\glpsol.obj glpk.lib
+        cl.exe $(CFLAGS) /Feglpsol.exe \
+                ..\examples\glpsol.obj glpk.lib
+
+check: glpsol.exe
+        .\glpsol.exe --version
+        .\glpsol.exe --mps ..\examples\plan.mps
+
+## eof ##
Index: deps/glpk/w32/Makefile_VC_DLL
===================================================================
--- deps/glpk/w32/Makefile_VC_DLL	(revision 9)
+++ deps/glpk/w32/Makefile_VC_DLL	(revision 9)
@@ -0,0 +1,169 @@
+## Build GLPK DLL with Microsoft Visual Studio Express ##
+
+CFLAGS = \
+/I. \
+/I..\src \
+/I..\src\amd \
+/I..\src\colamd \
+/I..\src\minisat \
+/I..\src\zlib \
+/DHAVE_CONFIG_H=1 \
+/D_CRT_SECURE_NO_WARNINGS=1 \
+/nologo \
+/W3 \
+/O2
+
+OBJSET = \
+..\src\glpapi01.obj \
+..\src\glpapi02.obj \
+..\src\glpapi03.obj \
+..\src\glpapi04.obj \
+..\src\glpapi05.obj \
+..\src\glpapi06.obj \
+..\src\glpapi07.obj \
+..\src\glpapi08.obj \
+..\src\glpapi09.obj \
+..\src\glpapi10.obj \
+..\src\glpapi11.obj \
+..\src\glpapi12.obj \
+..\src\glpapi13.obj \
+..\src\glpapi14.obj \
+..\src\glpapi15.obj \
+..\src\glpapi16.obj \
+..\src\glpapi17.obj \
+..\src\glpapi18.obj \
+..\src\glpapi19.obj \
+..\src\glpapi20.obj \
+..\src\glpapi21.obj \
+..\src\glpavl.obj \
+..\src\glpbfd.obj \
+..\src\glpbfx.obj \
+..\src\glpcpx.obj \
+..\src\glpdmp.obj \
+..\src\glpdmx.obj \
+..\src\glpenv01.obj \
+..\src\glpenv02.obj \
+..\src\glpenv03.obj \
+..\src\glpenv04.obj \
+..\src\glpenv05.obj \
+..\src\glpenv06.obj \
+..\src\glpenv07.obj \
+..\src\glpenv08.obj \
+..\src\glpfhv.obj \
+..\src\glpgmp.obj \
+..\src\glphbm.obj \
+..\src\glpini01.obj \
+..\src\glpini02.obj \
+..\src\glpios01.obj \
+..\src\glpios02.obj \
+..\src\glpios03.obj \
+..\src\glpios04.obj \
+..\src\glpios05.obj \
+..\src\glpios06.obj \
+..\src\glpios07.obj \
+..\src\glpios08.obj \
+..\src\glpios09.obj \
+..\src\glpios10.obj \
+..\src\glpios11.obj \
+..\src\glpios12.obj \
+..\src\glpipm.obj \
+..\src\glplib01.obj \
+..\src\glplib02.obj \
+..\src\glplib03.obj \
+..\src\glplpf.obj \
+..\src\glplpx01.obj \
+..\src\glplpx02.obj \
+..\src\glplpx03.obj \
+..\src\glpluf.obj \
+..\src\glplux.obj \
+..\src\glpmat.obj \
+..\src\glpmpl01.obj \
+..\src\glpmpl02.obj \
+..\src\glpmpl03.obj \
+..\src\glpmpl04.obj \
+..\src\glpmpl05.obj \
+..\src\glpmpl06.obj \
+..\src\glpmps.obj \
+..\src\glpnet01.obj \
+..\src\glpnet02.obj \
+..\src\glpnet03.obj \
+..\src\glpnet04.obj \
+..\src\glpnet05.obj \
+..\src\glpnet06.obj \
+..\src\glpnet07.obj \
+..\src\glpnet08.obj \
+..\src\glpnet09.obj \
+..\src\glpnpp01.obj \
+..\src\glpnpp02.obj \
+..\src\glpnpp03.obj \
+..\src\glpnpp04.obj \
+..\src\glpnpp05.obj \
+..\src\glpnpp06.obj \
+..\src\glpqmd.obj \
+..\src\glprgr.obj \
+..\src\glprng01.obj \
+..\src\glprng02.obj \
+..\src\glpscf.obj \
+..\src\glpscl.obj \
+..\src\glpsdf.obj \
+..\src\glpspm.obj \
+..\src\glpspx01.obj \
+..\src\glpspx02.obj \
+..\src\glpsql.obj \
+..\src\glpssx01.obj \
+..\src\glpssx02.obj \
+..\src\glptsp.obj \
+..\src\amd\amd_1.obj \
+..\src\amd\amd_2.obj \
+..\src\amd\amd_aat.obj \
+..\src\amd\amd_control.obj \
+..\src\amd\amd_defaults.obj \
+..\src\amd\amd_dump.obj \
+..\src\amd\amd_info.obj \
+..\src\amd\amd_order.obj \
+..\src\amd\amd_post_tree.obj \
+..\src\amd\amd_postorder.obj \
+..\src\amd\amd_preprocess.obj \
+..\src\amd\amd_valid.obj \
+..\src\colamd\colamd.obj \
+..\src\minisat\minisat.obj \
+..\src\zlib\adler32.obj \
+..\src\zlib\compress.obj \
+..\src\zlib\crc32.obj \
+..\src\zlib\deflate.obj \
+..\src\zlib\gzclose.obj \
+..\src\zlib\gzlib.obj \
+..\src\zlib\gzread.obj \
+..\src\zlib\gzwrite.obj \
+..\src\zlib\infback.obj \
+..\src\zlib\inffast.obj \
+..\src\zlib\inflate.obj \
+..\src\zlib\inftrees.obj \
+..\src\zlib\trees.obj \
+..\src\zlib\uncompr.obj \
+..\src\zlib\zio.obj \
+..\src\zlib\zutil.obj
+
+.c.obj:
+        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
+
+all: glpk_4_47.dll glpsol.exe
+
+glpk_4_47.dll: $(OBJSET)
+        cl.exe $(CFLAGS) /LD /Feglpk_4_47.dll \
+                ..\src\*.obj \
+                ..\src\amd\*.obj \
+                ..\src\colamd\*.obj \
+                ..\src\minisat\*.obj \
+                ..\src\zlib\*.obj \
+                glpk_4_47.def
+
+glpsol.exe: ..\examples\glpsol.obj glpk_4_47.dll
+        cl.exe $(CFLAGS) /Feglpsol.exe \
+                ..\examples\glpsol.obj glpk_4_47.lib
+
+check: glpsol.exe
+        .\glpsol.exe --version
+        .\glpsol.exe --mps ..\examples\plan.mps
+
+## eof ##
Index: deps/glpk/w32/config_VC
===================================================================
--- deps/glpk/w32/config_VC	(revision 9)
+++ deps/glpk/w32/config_VC	(revision 9)
@@ -0,0 +1,13 @@
+/* GLPK configuration file (Microsoft Visual Studio Express) */
+
+#define __WOE__ 1
+
+#define ODBC_DLNAME "odbc32.dll"
+/* ODBC shared library name if this feature is enabled */
+
+#if 0
+#define MYSQL_DLNAME "libmysql.dll"
+/* MySQL shared library name if this feature is enabled */
+#endif
+
+/* eof */
Index: deps/glpk/w32/glpk_4_47.def
===================================================================
--- deps/glpk/w32/glpk_4_47.def	(revision 9)
+++ deps/glpk/w32/glpk_4_47.def	(revision 9)
@@ -0,0 +1,1210 @@
+LIBRARY glpk_4_47
+VERSION 4.47
+DESCRIPTION "GNU Linear Programming Kit"
+EXPORTS
+;; from adler32 ;;
+ _glp_zlib_adler32
+ _glp_zlib_adler32_combine
+ _glp_zlib_adler32_combine64
+;; from amd_1 ;;
+ _glp_amd_1
+;; from amd_2 ;;
+ _glp_amd_2
+;; from amd_aat ;;
+ _glp_amd_aat
+;; from amd_control ;;
+ _glp_amd_control
+;; from amd_defaults ;;
+ _glp_amd_defaults
+;; from amd_dump ;;
+;; from amd_info ;;
+ _glp_amd_info
+;; from amd_order ;;
+ _glp_amd_order
+;; from amd_post_tree ;;
+ _glp_amd_post_tree
+;; from amd_postorder ;;
+ _glp_amd_postorder
+;; from amd_preprocess ;;
+ _glp_amd_preprocess
+;; from amd_valid ;;
+ _glp_amd_valid
+;; from colamd ;;
+ _glp_colamd
+ _glp_colamd_recommended
+ _glp_colamd_report
+ _glp_colamd_set_defaults
+ _glp_symamd
+ _glp_symamd_report
+;; from compress ;;
+ _glp_zlib_compress
+ _glp_zlib_compress2
+ _glp_zlib_compressBound
+;; from crc32 ;;
+ _glp_zlib_crc32
+ _glp_zlib_crc32_combine
+ _glp_zlib_crc32_combine64
+ _glp_zlib_get_crc_table
+;; from deflate ;;
+ _glp_zlib_deflate
+ _glp_zlib_deflateBound
+ _glp_zlib_deflateCopy
+ _glp_zlib_deflateEnd
+ _glp_zlib_deflateInit2_
+ _glp_zlib_deflateInit_
+ _glp_zlib_deflateParams
+ _glp_zlib_deflatePrime
+ _glp_zlib_deflateReset
+ _glp_zlib_deflateSetDictionary
+ _glp_zlib_deflateSetHeader
+ _glp_zlib_deflateTune
+ _glp_zlib_deflate_copyright
+;; from glpapi01 ;;
+ glp_add_cols
+ glp_add_rows
+ glp_check_dup
+ glp_copy_prob
+ glp_create_prob
+ glp_del_cols
+ glp_del_rows
+ glp_delete_prob
+ glp_erase_prob
+ glp_load_matrix
+ glp_set_col_bnds
+ glp_set_col_name
+ glp_set_mat_col
+ glp_set_mat_row
+ glp_set_obj_coef
+ glp_set_obj_dir
+ glp_set_obj_name
+ glp_set_prob_name
+ glp_set_row_bnds
+ glp_set_row_name
+ glp_sort_matrix
+;; from glpapi02 ;;
+ glp_get_col_lb
+ glp_get_col_name
+ glp_get_col_type
+ glp_get_col_ub
+ glp_get_mat_col
+ glp_get_mat_row
+ glp_get_num_cols
+ glp_get_num_nz
+ glp_get_num_rows
+ glp_get_obj_coef
+ glp_get_obj_dir
+ glp_get_obj_name
+ glp_get_prob_name
+ glp_get_row_lb
+ glp_get_row_name
+ glp_get_row_type
+ glp_get_row_ub
+;; from glpapi03 ;;
+ glp_create_index
+ glp_delete_index
+ glp_find_col
+ glp_find_row
+;; from glpapi04 ;;
+ glp_get_rii
+ glp_get_sjj
+ glp_set_rii
+ glp_set_sjj
+ glp_unscale_prob
+;; from glpapi05 ;;
+ glp_set_col_stat
+ glp_set_row_stat
+ glp_std_basis
+;; from glpapi06 ;;
+ glp_get_col_dual
+ glp_get_col_prim
+ glp_get_col_stat
+ glp_get_dual_stat
+ glp_get_obj_val
+ glp_get_prim_stat
+ glp_get_row_dual
+ glp_get_row_prim
+ glp_get_row_stat
+ glp_get_status
+ glp_get_unbnd_ray
+ glp_init_smcp
+ glp_simplex
+;; from glpapi07 ;;
+ glp_exact
+;; from glpapi08 ;;
+ glp_init_iptcp
+ glp_interior
+ glp_ipt_col_dual
+ glp_ipt_col_prim
+ glp_ipt_obj_val
+ glp_ipt_row_dual
+ glp_ipt_row_prim
+ glp_ipt_status
+;; from glpapi09 ;;
+ _glp_intopt1
+ glp_get_col_kind
+ glp_get_num_bin
+ glp_get_num_int
+ glp_init_iocp
+ glp_intopt
+ glp_mip_col_val
+ glp_mip_obj_val
+ glp_mip_row_val
+ glp_mip_status
+ glp_set_col_kind
+;; from glpapi10 ;;
+ _glp_check_kkt
+;; from glpapi11 ;;
+ glp_print_ipt
+ glp_print_mip
+ glp_print_ranges
+ glp_print_sol
+ glp_read_ipt
+ glp_read_mip
+ glp_read_sol
+ glp_write_ipt
+ glp_write_mip
+ glp_write_sol
+;; from glpapi12 ;;
+ _glp_analyze_row
+ glp_analyze_bound
+ glp_analyze_coef
+ glp_bf_exists
+ glp_bf_updated
+ glp_btran
+ glp_dual_rtest
+ glp_eval_tab_col
+ glp_eval_tab_row
+ glp_factorize
+ glp_ftran
+ glp_get_bfcp
+ glp_get_bhead
+ glp_get_col_bind
+ glp_get_row_bind
+ glp_prim_rtest
+ glp_set_bfcp
+ glp_transform_col
+ glp_transform_row
+ glp_warm_up
+;; from glpapi13 ;;
+ glp_ios_add_row
+ glp_ios_best_node
+ glp_ios_branch_upon
+ glp_ios_can_branch
+ glp_ios_clear_pool
+ glp_ios_curr_node
+ glp_ios_del_row
+ glp_ios_get_prob
+ glp_ios_heur_sol
+ glp_ios_mip_gap
+ glp_ios_next_node
+ glp_ios_node_bound
+ glp_ios_node_data
+ glp_ios_node_level
+ glp_ios_pool_size
+ glp_ios_prev_node
+ glp_ios_reason
+ glp_ios_row_attr
+ glp_ios_select_node
+ glp_ios_terminate
+ glp_ios_tree_size
+ glp_ios_up_node
+;; from glpapi14 ;;
+ _glp_mpl_init_rand
+ glp_mpl_alloc_wksp
+ glp_mpl_build_prob
+ glp_mpl_free_wksp
+ glp_mpl_generate
+ glp_mpl_postsolve
+ glp_mpl_read_data
+ glp_mpl_read_model
+;; from glpapi15 ;;
+ glp_add_arc
+ glp_add_vertices
+ glp_create_graph
+ glp_create_v_index
+ glp_del_arc
+ glp_del_vertices
+ glp_delete_graph
+ glp_delete_v_index
+ glp_erase_graph
+ glp_find_vertex
+ glp_read_graph
+ glp_set_graph_name
+ glp_set_vertex_name
+ glp_write_graph
+;; from glpapi16 ;;
+ glp_strong_comp
+ glp_top_sort
+ glp_weak_comp
+;; from glpapi17 ;;
+ glp_asnprob_hall
+ glp_asnprob_lp
+ glp_asnprob_okalg
+ glp_check_asnprob
+ glp_cpp
+ glp_maxflow_ffalg
+ glp_maxflow_lp
+ glp_mincost_lp
+ glp_mincost_okalg
+;; from glpapi18 ;;
+ glp_wclique_exact
+;; from glpapi19 ;;
+ glp_minisat1
+;; from glpapi20 ;;
+ glp_intfeas1
+;; from glpapi21 ;;
+ glp_main
+;; from glpavl ;;
+ _glp_avl_create_tree
+ _glp_avl_delete_node
+ _glp_avl_delete_tree
+ _glp_avl_find_node
+ _glp_avl_get_node_link
+ _glp_avl_get_node_type
+ _glp_avl_insert_node
+ _glp_avl_set_node_link
+ _glp_avl_set_node_type
+ _glp_avl_strcmp
+;; from glpbfd ;;
+ _glp_bfd_btran
+ _glp_bfd_create_it
+ _glp_bfd_delete_it
+ _glp_bfd_factorize
+ _glp_bfd_ftran
+ _glp_bfd_get_count
+ _glp_bfd_set_parm
+ _glp_bfd_update_it
+;; from glpbfx ;;
+ _glp_bfx_btran
+ _glp_bfx_create_binv
+ _glp_bfx_delete_binv
+ _glp_bfx_factorize
+ _glp_bfx_ftran
+ _glp_bfx_update
+;; from glpcpx ;;
+ glp_init_cpxcp
+ glp_read_lp
+ glp_write_lp
+;; from glpdmp ;;
+ _glp_dmp_create_pool
+ _glp_dmp_delete_pool
+ _glp_dmp_free_atom
+ _glp_dmp_get_atom
+ _glp_dmp_in_use
+;; from glpdmx ;;
+ glp_check_cnfsat
+ glp_read_asnprob
+ glp_read_ccdata
+ glp_read_cnfsat
+ glp_read_maxflow
+ glp_read_mincost
+ glp_read_prob
+ glp_write_asnprob
+ glp_write_ccdata
+ glp_write_cnfsat
+ glp_write_maxflow
+ glp_write_mincost
+ glp_write_prob
+;; from glpenv01 ;;
+ _glp_get_env_ptr
+ glp_free_env
+ glp_init_env
+ glp_version
+;; from glpenv02 ;;
+ _glp_tls_get_ptr
+ _glp_tls_set_ptr
+;; from glpenv03 ;;
+ glp_close_tee
+ glp_open_tee
+ glp_printf
+ glp_term_hook
+ glp_term_out
+ glp_vprintf
+;; from glpenv04 ;;
+ glp_assert_
+ glp_error_
+ glp_error_hook
+;; from glpenv05 ;;
+ glp_calloc
+ glp_free
+ glp_malloc
+ glp_mem_limit
+ glp_mem_usage
+;; from glpenv06 ;;
+ glp_difftime
+ glp_time
+;; from glpenv07 ;;
+ _glp_lib_err_msg
+ _glp_lib_xerrmsg
+ _glp_lib_xfclose
+ _glp_lib_xfeof
+ _glp_lib_xferror
+ _glp_lib_xfflush
+ _glp_lib_xfgetc
+ _glp_lib_xfopen
+ _glp_lib_xfprintf
+ _glp_lib_xfputc
+;; from glpenv08 ;;
+ _glp_xdlclose
+ _glp_xdlopen
+ _glp_xdlsym
+;; from glpfhv ;;
+ _glp_fhv_btran
+ _glp_fhv_create_it
+ _glp_fhv_delete_it
+ _glp_fhv_factorize
+ _glp_fhv_ftran
+ _glp_fhv_h_solve
+ _glp_fhv_update_it
+;; from glpgmp ;;
+ _glp_gmp_free_atom
+ _glp_gmp_free_mem
+ _glp_gmp_get_atom
+ _glp_gmp_get_work
+ _glp_gmp_pool_count
+ _glp_mpq_abs
+ _glp_mpq_add
+ _glp_mpq_canonicalize
+ _glp_mpq_clear
+ _glp_mpq_cmp
+ _glp_mpq_div
+ _glp_mpq_get_d
+ _glp_mpq_init
+ _glp_mpq_mul
+ _glp_mpq_neg
+ _glp_mpq_out_str
+ _glp_mpq_set
+ _glp_mpq_set_d
+ _glp_mpq_set_si
+ _glp_mpq_sgn
+ _glp_mpq_sub
+ _glp_mpz_abs
+ _glp_mpz_add
+ _glp_mpz_clear
+ _glp_mpz_cmp
+ _glp_mpz_div
+ _glp_mpz_gcd
+ _glp_mpz_get_d
+ _glp_mpz_get_d_2exp
+ _glp_mpz_init
+ _glp_mpz_mul
+ _glp_mpz_neg
+ _glp_mpz_out_str
+ _glp_mpz_set
+ _glp_mpz_set_si
+ _glp_mpz_sgn
+ _glp_mpz_sub
+ _glp_mpz_swap
+;; from glphbm ;;
+ _glp_hbm_free_mat
+ _glp_hbm_read_mat
+;; from glpini01 ;;
+ glp_adv_basis
+;; from glpini02 ;;
+ glp_cpx_basis
+;; from glpios01 ;;
+ _glp_ios_add_row
+ _glp_ios_best_node
+ _glp_ios_clear_pool
+ _glp_ios_clone_node
+ _glp_ios_create_pool
+ _glp_ios_create_tree
+ _glp_ios_del_row
+ _glp_ios_delete_node
+ _glp_ios_delete_pool
+ _glp_ios_delete_tree
+ _glp_ios_eval_degrad
+ _glp_ios_find_row
+ _glp_ios_freeze_node
+ _glp_ios_is_hopeful
+ _glp_ios_relative_gap
+ _glp_ios_revive_node
+ _glp_ios_round_bound
+ _glp_ios_solve_node
+;; from glpios02 ;;
+ _glp_ios_preprocess_node
+;; from glpios03 ;;
+ _glp_ios_driver
+;; from glpios04 ;;
+ _glp_ios_check_vec
+ _glp_ios_clean_vec
+ _glp_ios_clear_vec
+ _glp_ios_copy_vec
+ _glp_ios_create_vec
+ _glp_ios_delete_vec
+ _glp_ios_get_vj
+ _glp_ios_linear_comb
+ _glp_ios_set_vj
+;; from glpios05 ;;
+ _glp_ios_gmi_gen
+;; from glpios06 ;;
+ _glp_ios_mir_gen
+ _glp_ios_mir_init
+ _glp_ios_mir_term
+;; from glpios07 ;;
+ _glp_ios_cov_gen
+;; from glpios08 ;;
+ _glp_ios_clq_gen
+ _glp_ios_clq_init
+ _glp_ios_clq_term
+;; from glpios09 ;;
+ _glp_ios_choose_var
+ _glp_ios_pcost_branch
+ _glp_ios_pcost_free
+ _glp_ios_pcost_init
+ _glp_ios_pcost_update
+;; from glpios10 ;;
+ _glp_ios_feas_pump
+;; from glpios11 ;;
+ _glp_ios_process_cuts
+;; from glpios12 ;;
+ _glp_ios_choose_node
+;; from glpipm ;;
+ _glp_ipm_solve
+;; from glplib01 ;;
+ _glp_lib_bigdiv
+ _glp_lib_bigmul
+;; from glplib02 ;;
+ _glp_lib_xladd
+ _glp_lib_xlcmp
+ _glp_lib_xldiv
+ _glp_lib_xlmul
+ _glp_lib_xlneg
+ _glp_lib_xlset
+ _glp_lib_xlsub
+ _glp_lib_xltoa
+ _glp_lib_xltod
+;; from glplib03 ;;
+ _glp_lib_fp2rat
+ _glp_lib_gcd
+ _glp_lib_gcdn
+ _glp_lib_jdate
+ _glp_lib_jday
+ _glp_lib_lcm
+ _glp_lib_lcmn
+ _glp_lib_round2n
+ _glp_lib_str2int
+ _glp_lib_str2num
+ _glp_lib_strrev
+ _glp_lib_strspx
+ _glp_lib_strtrim
+;; from glplpf ;;
+ _glp_lpf_btran
+ _glp_lpf_create_it
+ _glp_lpf_delete_it
+ _glp_lpf_factorize
+ _glp_lpf_ftran
+ _glp_lpf_update_it
+;; from glplpx01 ;;
+ _glp_lpx_add_cols
+ _glp_lpx_add_rows
+ _glp_lpx_adv_basis
+ _glp_lpx_check_int
+ _glp_lpx_check_kkt
+ _glp_lpx_cpx_basis
+ _glp_lpx_create_index
+ _glp_lpx_create_prob
+ _glp_lpx_del_cols
+ _glp_lpx_del_rows
+ _glp_lpx_delete_index
+ _glp_lpx_delete_prob
+ _glp_lpx_dual_ratio_test
+ _glp_lpx_eval_tab_col
+ _glp_lpx_eval_tab_row
+ _glp_lpx_exact
+ _glp_lpx_find_col
+ _glp_lpx_find_row
+ _glp_lpx_get_class
+ _glp_lpx_get_col_bnds
+ _glp_lpx_get_col_dual
+ _glp_lpx_get_col_info
+ _glp_lpx_get_col_kind
+ _glp_lpx_get_col_lb
+ _glp_lpx_get_col_name
+ _glp_lpx_get_col_prim
+ _glp_lpx_get_col_stat
+ _glp_lpx_get_col_type
+ _glp_lpx_get_col_ub
+ _glp_lpx_get_dual_stat
+ _glp_lpx_get_int_parm
+ _glp_lpx_get_mat_col
+ _glp_lpx_get_mat_row
+ _glp_lpx_get_num_bin
+ _glp_lpx_get_num_cols
+ _glp_lpx_get_num_int
+ _glp_lpx_get_num_nz
+ _glp_lpx_get_num_rows
+ _glp_lpx_get_obj_coef
+ _glp_lpx_get_obj_dir
+ _glp_lpx_get_obj_name
+ _glp_lpx_get_obj_val
+ _glp_lpx_get_prim_stat
+ _glp_lpx_get_prob_name
+ _glp_lpx_get_ray_info
+ _glp_lpx_get_real_parm
+ _glp_lpx_get_row_bnds
+ _glp_lpx_get_row_dual
+ _glp_lpx_get_row_info
+ _glp_lpx_get_row_lb
+ _glp_lpx_get_row_name
+ _glp_lpx_get_row_prim
+ _glp_lpx_get_row_stat
+ _glp_lpx_get_row_type
+ _glp_lpx_get_row_ub
+ _glp_lpx_get_status
+ _glp_lpx_integer
+ _glp_lpx_interior
+ _glp_lpx_intopt
+ _glp_lpx_ipt_col_dual
+ _glp_lpx_ipt_col_prim
+ _glp_lpx_ipt_obj_val
+ _glp_lpx_ipt_row_dual
+ _glp_lpx_ipt_row_prim
+ _glp_lpx_ipt_status
+ _glp_lpx_is_b_avail
+ _glp_lpx_load_matrix
+ _glp_lpx_main
+ _glp_lpx_mip_col_val
+ _glp_lpx_mip_obj_val
+ _glp_lpx_mip_row_val
+ _glp_lpx_mip_status
+ _glp_lpx_prim_ratio_test
+ _glp_lpx_print_ips
+ _glp_lpx_print_mip
+ _glp_lpx_print_prob
+ _glp_lpx_print_sens_bnds
+ _glp_lpx_print_sol
+ _glp_lpx_read_bas
+ _glp_lpx_read_cpxlp
+ _glp_lpx_read_freemps
+ _glp_lpx_read_model
+ _glp_lpx_read_mps
+ _glp_lpx_reset_parms
+ _glp_lpx_scale_prob
+ _glp_lpx_set_class
+ _glp_lpx_set_col_bnds
+ _glp_lpx_set_col_kind
+ _glp_lpx_set_col_name
+ _glp_lpx_set_col_stat
+ _glp_lpx_set_int_parm
+ _glp_lpx_set_mat_col
+ _glp_lpx_set_mat_row
+ _glp_lpx_set_obj_coef
+ _glp_lpx_set_obj_dir
+ _glp_lpx_set_obj_name
+ _glp_lpx_set_prob_name
+ _glp_lpx_set_real_parm
+ _glp_lpx_set_row_bnds
+ _glp_lpx_set_row_name
+ _glp_lpx_set_row_stat
+ _glp_lpx_simplex
+ _glp_lpx_std_basis
+ _glp_lpx_transform_col
+ _glp_lpx_transform_row
+ _glp_lpx_unscale_prob
+ _glp_lpx_warm_up
+ _glp_lpx_write_bas
+ _glp_lpx_write_cpxlp
+ _glp_lpx_write_freemps
+ _glp_lpx_write_mps
+;; from glplpx02 ;;
+ _glp_put_mip_soln
+ _glp_put_solution
+;; from glplpx03 ;;
+ _glp_lpx_write_pb
+;; from glpluf ;;
+ _glp_luf_a_solve
+ _glp_luf_create_it
+ _glp_luf_defrag_sva
+ _glp_luf_delete_it
+ _glp_luf_enlarge_col
+ _glp_luf_enlarge_row
+ _glp_luf_f_solve
+ _glp_luf_factorize
+ _glp_luf_v_solve
+;; from glplux ;;
+ _glp_lux_create
+ _glp_lux_decomp
+ _glp_lux_delete
+ _glp_lux_f_solve
+ _glp_lux_solve
+ _glp_lux_v_solve
+;; from glpmat ;;
+ _glp_mat_adat_numeric
+ _glp_mat_adat_symbolic
+ _glp_mat_amd_order1
+ _glp_mat_check_fvs
+ _glp_mat_check_pattern
+ _glp_mat_chol_numeric
+ _glp_mat_chol_symbolic
+ _glp_mat_min_degree
+ _glp_mat_symamd_ord
+ _glp_mat_transpose
+ _glp_mat_u_solve
+ _glp_mat_ut_solve
+;; from glpmpl01 ;;
+ _glp_mpl_append_block
+ _glp_mpl_append_char
+ _glp_mpl_append_slot
+ _glp_mpl_arg_list_len
+ _glp_mpl_branched_expression
+ _glp_mpl_check_statement
+ _glp_mpl_close_scope
+ _glp_mpl_constraint_statement
+ _glp_mpl_create_arg_list
+ _glp_mpl_create_block
+ _glp_mpl_create_domain
+ _glp_mpl_display_statement
+ _glp_mpl_domain_arity
+ _glp_mpl_elemset_argument
+ _glp_mpl_end_statement
+ _glp_mpl_enter_context
+ _glp_mpl_error_dimension
+ _glp_mpl_error_following
+ _glp_mpl_error_preceding
+ _glp_mpl_expand_arg_list
+ _glp_mpl_expression_0
+ _glp_mpl_expression_1
+ _glp_mpl_expression_10
+ _glp_mpl_expression_11
+ _glp_mpl_expression_12
+ _glp_mpl_expression_13
+ _glp_mpl_expression_2
+ _glp_mpl_expression_3
+ _glp_mpl_expression_4
+ _glp_mpl_expression_5
+ _glp_mpl_expression_6
+ _glp_mpl_expression_7
+ _glp_mpl_expression_8
+ _glp_mpl_expression_9
+ _glp_mpl_expression_list
+ _glp_mpl_for_statement
+ _glp_mpl_function_reference
+ _glp_mpl_get_char
+ _glp_mpl_get_token
+ _glp_mpl_indexing_expression
+ _glp_mpl_is_keyword
+ _glp_mpl_is_reserved
+ _glp_mpl_iterated_expression
+ _glp_mpl_literal_set
+ _glp_mpl_make_binary
+ _glp_mpl_make_code
+ _glp_mpl_make_ternary
+ _glp_mpl_make_unary
+ _glp_mpl_model_section
+ _glp_mpl_numeric_argument
+ _glp_mpl_numeric_literal
+ _glp_mpl_object_reference
+ _glp_mpl_objective_statement
+ _glp_mpl_parameter_statement
+ _glp_mpl_primary_expression
+ _glp_mpl_print_context
+ _glp_mpl_printf_statement
+ _glp_mpl_set_expression
+ _glp_mpl_set_statement
+ _glp_mpl_simple_statement
+ _glp_mpl_solve_statement
+ _glp_mpl_string_literal
+ _glp_mpl_subscript_list
+ _glp_mpl_symbolic_argument
+ _glp_mpl_table_statement
+ _glp_mpl_unget_token
+ _glp_mpl_variable_statement
+;; from glpmpl02 ;;
+ _glp_mpl_create_slice
+ _glp_mpl_data_section
+ _glp_mpl_delete_slice
+ _glp_mpl_expand_slice
+ _glp_mpl_fake_slice
+ _glp_mpl_is_literal
+ _glp_mpl_is_number
+ _glp_mpl_is_symbol
+ _glp_mpl_matrix_format
+ _glp_mpl_parameter_data
+ _glp_mpl_plain_format
+ _glp_mpl_read_number
+ _glp_mpl_read_slice
+ _glp_mpl_read_symbol
+ _glp_mpl_read_value
+ _glp_mpl_select_parameter
+ _glp_mpl_select_set
+ _glp_mpl_set_data
+ _glp_mpl_set_default
+ _glp_mpl_simple_format
+ _glp_mpl_slice_arity
+ _glp_mpl_slice_dimen
+ _glp_mpl_tabbing_format
+ _glp_mpl_tabular_format
+;; from glpmpl03 ;;
+ _glp_mpl_add_member
+ _glp_mpl_add_tuple
+ _glp_mpl_arelset_member
+ _glp_mpl_arelset_size
+ _glp_mpl_assign_dummy_index
+ _glp_mpl_build_subtuple
+ _glp_mpl_check_elem_set
+ _glp_mpl_check_then_add
+ _glp_mpl_check_value_num
+ _glp_mpl_check_value_sym
+ _glp_mpl_clean_check
+ _glp_mpl_clean_code
+ _glp_mpl_clean_constraint
+ _glp_mpl_clean_display
+ _glp_mpl_clean_domain
+ _glp_mpl_clean_for
+ _glp_mpl_clean_parameter
+ _glp_mpl_clean_printf
+ _glp_mpl_clean_set
+ _glp_mpl_clean_statement
+ _glp_mpl_clean_table
+ _glp_mpl_clean_variable
+ _glp_mpl_compare_strings
+ _glp_mpl_compare_symbols
+ _glp_mpl_compare_tuples
+ _glp_mpl_concat_symbols
+ _glp_mpl_constant_term
+ _glp_mpl_copy_elemset
+ _glp_mpl_copy_formula
+ _glp_mpl_copy_string
+ _glp_mpl_copy_symbol
+ _glp_mpl_copy_tuple
+ _glp_mpl_create_arelset
+ _glp_mpl_create_array
+ _glp_mpl_create_elemset
+ _glp_mpl_create_string
+ _glp_mpl_create_symbol_num
+ _glp_mpl_create_symbol_str
+ _glp_mpl_create_tuple
+ _glp_mpl_delete_array
+ _glp_mpl_delete_elemset
+ _glp_mpl_delete_formula
+ _glp_mpl_delete_string
+ _glp_mpl_delete_symbol
+ _glp_mpl_delete_tuple
+ _glp_mpl_delete_value
+ _glp_mpl_enter_domain_block
+ _glp_mpl_eval_elemset
+ _glp_mpl_eval_formula
+ _glp_mpl_eval_logical
+ _glp_mpl_eval_member_con
+ _glp_mpl_eval_member_num
+ _glp_mpl_eval_member_set
+ _glp_mpl_eval_member_sym
+ _glp_mpl_eval_member_var
+ _glp_mpl_eval_numeric
+ _glp_mpl_eval_symbolic
+ _glp_mpl_eval_tuple
+ _glp_mpl_eval_whole_con
+ _glp_mpl_eval_whole_par
+ _glp_mpl_eval_whole_set
+ _glp_mpl_eval_whole_var
+ _glp_mpl_eval_within_domain
+ _glp_mpl_execute_check
+ _glp_mpl_execute_display
+ _glp_mpl_execute_for
+ _glp_mpl_execute_printf
+ _glp_mpl_execute_statement
+ _glp_mpl_execute_table
+ _glp_mpl_expand_tuple
+ _glp_mpl_fetch_string
+ _glp_mpl_find_member
+ _glp_mpl_find_tuple
+ _glp_mpl_format_symbol
+ _glp_mpl_format_tuple
+ _glp_mpl_fp_add
+ _glp_mpl_fp_atan
+ _glp_mpl_fp_atan2
+ _glp_mpl_fp_cos
+ _glp_mpl_fp_div
+ _glp_mpl_fp_exp
+ _glp_mpl_fp_idiv
+ _glp_mpl_fp_irand224
+ _glp_mpl_fp_less
+ _glp_mpl_fp_log
+ _glp_mpl_fp_log10
+ _glp_mpl_fp_mod
+ _glp_mpl_fp_mul
+ _glp_mpl_fp_normal
+ _glp_mpl_fp_normal01
+ _glp_mpl_fp_power
+ _glp_mpl_fp_round
+ _glp_mpl_fp_sin
+ _glp_mpl_fp_sqrt
+ _glp_mpl_fp_sub
+ _glp_mpl_fp_trunc
+ _glp_mpl_fp_uniform01
+ _glp_mpl_free_dca
+ _glp_mpl_get_domain_tuple
+ _glp_mpl_is_member
+ _glp_mpl_linear_comb
+ _glp_mpl_loop_within_domain
+ _glp_mpl_out_of_domain
+ _glp_mpl_reduce_terms
+ _glp_mpl_remove_constant
+ _glp_mpl_set_cross
+ _glp_mpl_set_diff
+ _glp_mpl_set_inter
+ _glp_mpl_set_symdiff
+ _glp_mpl_set_union
+ _glp_mpl_single_variable
+ _glp_mpl_tab_get_arg
+ _glp_mpl_tab_get_name
+ _glp_mpl_tab_get_num
+ _glp_mpl_tab_get_str
+ _glp_mpl_tab_get_type
+ _glp_mpl_tab_num_args
+ _glp_mpl_tab_num_flds
+ _glp_mpl_tab_set_num
+ _glp_mpl_tab_set_str
+ _glp_mpl_take_member_con
+ _glp_mpl_take_member_num
+ _glp_mpl_take_member_set
+ _glp_mpl_take_member_sym
+ _glp_mpl_take_member_var
+ _glp_mpl_tuple_dimen
+ _glp_mpl_uniform
+ _glp_mpl_update_dummy_indices
+;; from glpmpl04 ;;
+ _glp_mpl_alloc_content
+ _glp_mpl_build_problem
+ _glp_mpl_clean_model
+ _glp_mpl_close_input
+ _glp_mpl_error
+ _glp_mpl_flush_output
+ _glp_mpl_generate
+ _glp_mpl_generate_model
+ _glp_mpl_get_col_bnds
+ _glp_mpl_get_col_kind
+ _glp_mpl_get_col_name
+ _glp_mpl_get_mat_row
+ _glp_mpl_get_num_cols
+ _glp_mpl_get_num_rows
+ _glp_mpl_get_prob_name
+ _glp_mpl_get_row_bnds
+ _glp_mpl_get_row_c0
+ _glp_mpl_get_row_kind
+ _glp_mpl_get_row_name
+ _glp_mpl_has_solve_stmt
+ _glp_mpl_initialize
+ _glp_mpl_open_input
+ _glp_mpl_open_output
+ _glp_mpl_postsolve
+ _glp_mpl_postsolve_model
+ _glp_mpl_put_col_soln
+ _glp_mpl_put_row_soln
+ _glp_mpl_read_char
+ _glp_mpl_read_data
+ _glp_mpl_read_model
+ _glp_mpl_terminate
+ _glp_mpl_warning
+ _glp_mpl_write_char
+ _glp_mpl_write_text
+;; from glpmpl05 ;;
+ _glp_mpl_fn_gmtime
+ _glp_mpl_fn_str2time
+ _glp_mpl_fn_time2str
+;; from glpmpl06 ;;
+ _glp_mpl_tab_drv_close
+ _glp_mpl_tab_drv_open
+ _glp_mpl_tab_drv_read
+ _glp_mpl_tab_drv_write
+;; from glpmps ;;
+ glp_init_mpscp
+ glp_read_mps
+ glp_write_mps
+;; from glpnet01 ;;
+ _glp_mc21a
+;; from glpnet02 ;;
+ _glp_mc13d
+;; from glpnet03 ;;
+ glp_netgen
+;; from glpnet04 ;;
+ glp_gridgen
+;; from glpnet05 ;;
+ glp_rmfgen
+;; from glpnet06 ;;
+ _glp_okalg
+;; from glpnet07 ;;
+ _glp_ffalg
+;; from glpnet08 ;;
+ _glp_wclique
+;; from glpnet09 ;;
+ _glp_kellerman
+;; from glpnpp01 ;;
+ _glp_npp_activate_col
+ _glp_npp_activate_row
+ _glp_npp_add_aij
+ _glp_npp_add_col
+ _glp_npp_add_row
+ _glp_npp_build_prob
+ _glp_npp_col_nnz
+ _glp_npp_create_wksp
+ _glp_npp_deactivate_col
+ _glp_npp_deactivate_row
+ _glp_npp_del_aij
+ _glp_npp_del_col
+ _glp_npp_del_row
+ _glp_npp_delete_wksp
+ _glp_npp_erase_row
+ _glp_npp_insert_col
+ _glp_npp_insert_row
+ _glp_npp_load_prob
+ _glp_npp_postprocess
+ _glp_npp_push_tse
+ _glp_npp_remove_col
+ _glp_npp_remove_row
+ _glp_npp_row_nnz
+ _glp_npp_unload_sol
+;; from glpnpp02 ;;
+ _glp_npp_dbnd_col
+ _glp_npp_fixed_col
+ _glp_npp_free_col
+ _glp_npp_free_row
+ _glp_npp_geq_row
+ _glp_npp_lbnd_col
+ _glp_npp_leq_row
+ _glp_npp_make_equality
+ _glp_npp_make_fixed
+ _glp_npp_ubnd_col
+;; from glpnpp03 ;;
+ _glp_npp_analyze_row
+ _glp_npp_empty_col
+ _glp_npp_empty_row
+ _glp_npp_eq_doublet
+ _glp_npp_eq_singlet
+ _glp_npp_forcing_row
+ _glp_npp_implied_bounds
+ _glp_npp_implied_free
+ _glp_npp_implied_lower
+ _glp_npp_implied_slack
+ _glp_npp_implied_upper
+ _glp_npp_implied_value
+ _glp_npp_inactive_bound
+ _glp_npp_ineq_singlet
+;; from glpnpp04 ;;
+ _glp_npp_binarize_prob
+ _glp_npp_hidden_covering
+ _glp_npp_hidden_packing
+ _glp_npp_implied_packing
+ _glp_npp_is_covering
+ _glp_npp_is_packing
+ _glp_npp_is_partitioning
+ _glp_npp_reduce_ineq_coef
+;; from glpnpp05 ;;
+ _glp_npp_clean_prob
+ _glp_npp_improve_bounds
+ _glp_npp_integer
+ _glp_npp_process_col
+ _glp_npp_process_prob
+ _glp_npp_process_row
+ _glp_npp_simplex
+;; from glpnpp06 ;;
+ _glp_npp_sat_encode_clause
+ _glp_npp_sat_encode_geq
+ _glp_npp_sat_encode_leq
+ _glp_npp_sat_encode_pack
+ _glp_npp_sat_encode_prob
+ _glp_npp_sat_encode_row
+ _glp_npp_sat_encode_sum2
+ _glp_npp_sat_encode_sum3
+ _glp_npp_sat_encode_sum_ax
+ _glp_npp_sat_fixed_col
+ _glp_npp_sat_free_row
+ _glp_npp_sat_is_bin_comb
+ _glp_npp_sat_is_cover_ineq
+ _glp_npp_sat_is_pack_ineq
+ _glp_npp_sat_is_partn_eq
+ _glp_npp_sat_normalize_clause
+ _glp_npp_sat_num_neg_coef
+ _glp_npp_sat_num_pos_coef
+ _glp_npp_sat_reverse_row
+ _glp_npp_sat_split_pack
+;; from glpqmd ;;
+ _glp_qmd_genqmd
+ _glp_qmd_qmdmrg
+ _glp_qmd_qmdqt
+ _glp_qmd_qmdrch
+ _glp_qmd_qmdupd
+;; from glprgr ;;
+ _glp_rgr_write_bmp16
+;; from glprng01 ;;
+ _glp_rng_create_rand
+ _glp_rng_delete_rand
+ _glp_rng_init_rand
+ _glp_rng_next_rand
+ _glp_rng_unif_rand
+;; from glprng02 ;;
+ _glp_rng_unif_01
+ _glp_rng_uniform
+;; from glpscf ;;
+ _glp_scf_create_it
+ _glp_scf_delete_it
+ _glp_scf_reset_it
+ _glp_scf_solve_it
+ _glp_scf_update_exp
+;; from glpscl ;;
+ glp_scale_prob
+;; from glpsdf ;;
+ glp_sdf_close_file
+ glp_sdf_error
+ glp_sdf_line
+ glp_sdf_open_file
+ glp_sdf_read_int
+ glp_sdf_read_item
+ glp_sdf_read_num
+ glp_sdf_read_text
+ glp_sdf_set_jump
+ glp_sdf_warning
+;; from glpspm ;;
+ _glp_spm_add_mat
+ _glp_spm_add_num
+ _glp_spm_add_sym
+ _glp_spm_check_per
+ _glp_spm_count_nnz
+ _glp_spm_create_mat
+ _glp_spm_create_per
+ _glp_spm_delete_mat
+ _glp_spm_delete_per
+ _glp_spm_drop_zeros
+ _glp_spm_mul_mat
+ _glp_spm_mul_num
+ _glp_spm_mul_sym
+ _glp_spm_new_elem
+ _glp_spm_read_hbm
+ _glp_spm_read_mat
+ _glp_spm_show_mat
+ _glp_spm_test_mat_d
+ _glp_spm_test_mat_e
+ _glp_spm_transpose
+ _glp_spm_write_mat
+;; from glpspx01 ;;
+ _glp_spx_primal
+;; from glpspx02 ;;
+ _glp_spx_dual
+;; from glpsql ;;
+ _glp_db_iodbc_close
+ _glp_db_iodbc_open
+ _glp_db_iodbc_read
+ _glp_db_iodbc_write
+ _glp_db_mysql_close
+ _glp_db_mysql_open
+ _glp_db_mysql_read
+ _glp_db_mysql_write
+;; from glpssx01 ;;
+ _glp_ssx_change_basis
+ _glp_ssx_chuzc
+ _glp_ssx_chuzr
+ _glp_ssx_create
+ _glp_ssx_delete
+ _glp_ssx_eval_bbar
+ _glp_ssx_eval_cbar
+ _glp_ssx_eval_col
+ _glp_ssx_eval_dj
+ _glp_ssx_eval_pi
+ _glp_ssx_eval_rho
+ _glp_ssx_eval_row
+ _glp_ssx_factorize
+ _glp_ssx_get_xNj
+ _glp_ssx_update_bbar
+ _glp_ssx_update_cbar
+ _glp_ssx_update_pi
+;; from glpssx02 ;;
+ _glp_ssx_driver
+ _glp_ssx_phase_I
+ _glp_ssx_phase_II
+;; from glptsp ;;
+ _glp_tsp_distance
+ _glp_tsp_free_data
+ _glp_tsp_read_data
+;; from gzclose ;;
+ _glp_zlib_gzclose
+;; from gzlib ;;
+ _glp_zlib_gz_error
+ _glp_zlib_gzbuffer
+ _glp_zlib_gzclearerr
+ _glp_zlib_gzdopen
+ _glp_zlib_gzeof
+ _glp_zlib_gzerror
+ _glp_zlib_gzoffset
+ _glp_zlib_gzoffset64
+ _glp_zlib_gzopen
+ _glp_zlib_gzopen64
+ _glp_zlib_gzrewind
+ _glp_zlib_gzseek
+ _glp_zlib_gzseek64
+ _glp_zlib_gztell
+ _glp_zlib_gztell64
+;; from gzread ;;
+ _glp_zlib_gzclose_r
+ _glp_zlib_gzdirect
+ _glp_zlib_gzgetc
+ _glp_zlib_gzgets
+ _glp_zlib_gzread
+ _glp_zlib_gzungetc
+;; from gzwrite ;;
+ _glp_zlib_gzclose_w
+ _glp_zlib_gzflush
+ _glp_zlib_gzprintf
+ _glp_zlib_gzputc
+ _glp_zlib_gzputs
+ _glp_zlib_gzsetparams
+ _glp_zlib_gzwrite
+;; from infback ;;
+ _glp_zlib_inflateBack
+ _glp_zlib_inflateBackEnd
+ _glp_zlib_inflateBackInit_
+;; from inffast ;;
+ _glp_zlib_inflate_fast
+;; from inflate ;;
+ _glp_zlib_inflate
+ _glp_zlib_inflateCopy
+ _glp_zlib_inflateEnd
+ _glp_zlib_inflateGetHeader
+ _glp_zlib_inflateInit2_
+ _glp_zlib_inflateInit_
+ _glp_zlib_inflateMark
+ _glp_zlib_inflatePrime
+ _glp_zlib_inflateReset
+ _glp_zlib_inflateReset2
+ _glp_zlib_inflateSetDictionary
+ _glp_zlib_inflateSync
+ _glp_zlib_inflateSyncPoint
+ _glp_zlib_inflateUndermine
+;; from inftrees ;;
+ _glp_zlib_inflate_copyright
+ _glp_zlib_inflate_table
+;; from minisat ;;
+ _glp_minisat_addclause
+ _glp_minisat_delete
+ _glp_minisat_nclauses
+ _glp_minisat_nconflicts
+ _glp_minisat_new
+ _glp_minisat_nvars
+ _glp_minisat_propagate
+ _glp_minisat_reducedb
+ _glp_minisat_setnvars
+ _glp_minisat_simplify
+ _glp_minisat_solve
+;; from trees ;;
+ _glp_zlib_dist_code
+ _glp_zlib_length_code
+ _glp_zlib_tr_align
+ _glp_zlib_tr_flush_block
+ _glp_zlib_tr_init
+ _glp_zlib_tr_stored_block
+ _glp_zlib_tr_tally
+;; from uncompr ;;
+ _glp_zlib_uncompress
+;; from zio ;;
+ _glp_zlib_close
+ _glp_zlib_lseek
+ _glp_zlib_open
+ _glp_zlib_read
+ _glp_zlib_write
+;; from zutil ;;
+ _glp_zlib_zError
+ _glp_zlib_z_errmsg
+ _glp_zlib_zcalloc
+ _glp_zlib_zcfree
+ _glp_zlib_zlibCompileFlags
+ _glp_zlib_zlibVersion
Index: deps/glpk/w32/readme.txt
===================================================================
--- deps/glpk/w32/readme.txt	(revision 9)
+++ deps/glpk/w32/readme.txt	(revision 9)
@@ -0,0 +1,24 @@
+This directory contains batch files and other stuff which you can use
+to build GLPK for 32-bit Windows with the native C/C++ compilers.
+
+Before running the batch file do the following:
+
+1. Make sure that you have installed the compiler you are going to use
+   to build GLPK.
+
+2. Look into corresponding batch file (just right-click it and choose
+   'Edit' in the popup menu; DO NOT choose 'Open'). Make sure that HOME
+   variable specifies correct path to the compiler directory; if not,
+   make necessary changes.
+
+To run the batch file just double-click it and wait a bit while the
+Make utility does its job. The message 'OPTIMAL SOLUTION FOUND' in the
+MS-DOS window means that all is OK. If you do not see it, something is
+wrong.
+
+Once GLPK has been successfully built, there must appear two files in
+this directory:
+
+glpk.lib, which is the GLPK object library, and
+
+glpsol.exe, which is the stand-alone GLPK LP/MIP solver.
Index: deps/glpk/w64/Build_GLPK_with_VC10.bat
===================================================================
--- deps/glpk/w64/Build_GLPK_with_VC10.bat	(revision 9)
+++ deps/glpk/w64/Build_GLPK_with_VC10.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK with Microsoft Visual Studio Express 2010
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC"
+
+call %HOME%\vcvarsall.bat x64
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC
+%HOME%\bin\nmake.exe /f Makefile_VC check
+
+pause
Index: deps/glpk/w64/Build_GLPK_with_VC10_DLL.bat
===================================================================
--- deps/glpk/w64/Build_GLPK_with_VC10_DLL.bat	(revision 9)
+++ deps/glpk/w64/Build_GLPK_with_VC10_DLL.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK DLL with Microsoft Visual Studio Express 2010
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC"
+
+call %HOME%\vcvarsall.bat x64
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
+
+pause
Index: deps/glpk/w64/Build_GLPK_with_VC9.bat
===================================================================
--- deps/glpk/w64/Build_GLPK_with_VC9.bat	(revision 9)
+++ deps/glpk/w64/Build_GLPK_with_VC9.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK with Microsoft Visual Studio Express 2008
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC"
+
+call %HOME%\bin\vcvars64.bat
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC
+%HOME%\bin\nmake.exe /f Makefile_VC check
+
+pause
Index: deps/glpk/w64/Build_GLPK_with_VC9_DLL.bat
===================================================================
--- deps/glpk/w64/Build_GLPK_with_VC9_DLL.bat	(revision 9)
+++ deps/glpk/w64/Build_GLPK_with_VC9_DLL.bat	(revision 9)
@@ -0,0 +1,11 @@
+rem Build GLPK DLL with Microsoft Visual Studio Express 2008
+
+rem NOTE: Make sure that HOME variable specifies correct path
+set HOME="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC"
+
+call %HOME%\bin\vcvars64.bat
+copy config_VC config.h
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL
+%HOME%\bin\nmake.exe /f Makefile_VC_DLL check
+
+pause
Index: deps/glpk/w64/config_VC
===================================================================
--- deps/glpk/w64/config_VC	(revision 9)
+++ deps/glpk/w64/config_VC	(revision 9)
@@ -0,0 +1,13 @@
+/* GLPK configuration file (Microsoft Visual Studio Express) */
+
+#define __WOE__ 1
+
+#define ODBC_DLNAME "odbc32.dll"
+/* ODBC shared library name if this feature is enabled */
+
+#if 0
+#define MYSQL_DLNAME "libmysql.dll"
+/* MySQL shared library name if this feature is enabled */
+#endif
+
+/* eof */
Index: deps/glpk/w64/glpk_4_47.def
===================================================================
--- deps/glpk/w64/glpk_4_47.def	(revision 9)
+++ deps/glpk/w64/glpk_4_47.def	(revision 9)
@@ -0,0 +1,1210 @@
+LIBRARY glpk_4_47
+VERSION 4.47
+DESCRIPTION "GNU Linear Programming Kit"
+EXPORTS
+;; from adler32 ;;
+ _glp_zlib_adler32
+ _glp_zlib_adler32_combine
+ _glp_zlib_adler32_combine64
+;; from amd_1 ;;
+ _glp_amd_1
+;; from amd_2 ;;
+ _glp_amd_2
+;; from amd_aat ;;
+ _glp_amd_aat
+;; from amd_control ;;
+ _glp_amd_control
+;; from amd_defaults ;;
+ _glp_amd_defaults
+;; from amd_dump ;;
+;; from amd_info ;;
+ _glp_amd_info
+;; from amd_order ;;
+ _glp_amd_order
+;; from amd_post_tree ;;
+ _glp_amd_post_tree
+;; from amd_postorder ;;
+ _glp_amd_postorder
+;; from amd_preprocess ;;
+ _glp_amd_preprocess
+;; from amd_valid ;;
+ _glp_amd_valid
+;; from colamd ;;
+ _glp_colamd
+ _glp_colamd_recommended
+ _glp_colamd_report
+ _glp_colamd_set_defaults
+ _glp_symamd
+ _glp_symamd_report
+;; from compress ;;
+ _glp_zlib_compress
+ _glp_zlib_compress2
+ _glp_zlib_compressBound
+;; from crc32 ;;
+ _glp_zlib_crc32
+ _glp_zlib_crc32_combine
+ _glp_zlib_crc32_combine64
+ _glp_zlib_get_crc_table
+;; from deflate ;;
+ _glp_zlib_deflate
+ _glp_zlib_deflateBound
+ _glp_zlib_deflateCopy
+ _glp_zlib_deflateEnd
+ _glp_zlib_deflateInit2_
+ _glp_zlib_deflateInit_
+ _glp_zlib_deflateParams
+ _glp_zlib_deflatePrime
+ _glp_zlib_deflateReset
+ _glp_zlib_deflateSetDictionary
+ _glp_zlib_deflateSetHeader
+ _glp_zlib_deflateTune
+ _glp_zlib_deflate_copyright
+;; from glpapi01 ;;
+ glp_add_cols
+ glp_add_rows
+ glp_check_dup
+ glp_copy_prob
+ glp_create_prob
+ glp_del_cols
+ glp_del_rows
+ glp_delete_prob
+ glp_erase_prob
+ glp_load_matrix
+ glp_set_col_bnds
+ glp_set_col_name
+ glp_set_mat_col
+ glp_set_mat_row
+ glp_set_obj_coef
+ glp_set_obj_dir
+ glp_set_obj_name
+ glp_set_prob_name
+ glp_set_row_bnds
+ glp_set_row_name
+ glp_sort_matrix
+;; from glpapi02 ;;
+ glp_get_col_lb
+ glp_get_col_name
+ glp_get_col_type
+ glp_get_col_ub
+ glp_get_mat_col
+ glp_get_mat_row
+ glp_get_num_cols
+ glp_get_num_nz
+ glp_get_num_rows
+ glp_get_obj_coef
+ glp_get_obj_dir
+ glp_get_obj_name
+ glp_get_prob_name
+ glp_get_row_lb
+ glp_get_row_name
+ glp_get_row_type
+ glp_get_row_ub
+;; from glpapi03 ;;
+ glp_create_index
+ glp_delete_index
+ glp_find_col
+ glp_find_row
+;; from glpapi04 ;;
+ glp_get_rii
+ glp_get_sjj
+ glp_set_rii
+ glp_set_sjj
+ glp_unscale_prob
+;; from glpapi05 ;;
+ glp_set_col_stat
+ glp_set_row_stat
+ glp_std_basis
+;; from glpapi06 ;;
+ glp_get_col_dual
+ glp_get_col_prim
+ glp_get_col_stat
+ glp_get_dual_stat
+ glp_get_obj_val
+ glp_get_prim_stat
+ glp_get_row_dual
+ glp_get_row_prim
+ glp_get_row_stat
+ glp_get_status
+ glp_get_unbnd_ray
+ glp_init_smcp
+ glp_simplex
+;; from glpapi07 ;;
+ glp_exact
+;; from glpapi08 ;;
+ glp_init_iptcp
+ glp_interior
+ glp_ipt_col_dual
+ glp_ipt_col_prim
+ glp_ipt_obj_val
+ glp_ipt_row_dual
+ glp_ipt_row_prim
+ glp_ipt_status
+;; from glpapi09 ;;
+ _glp_intopt1
+ glp_get_col_kind
+ glp_get_num_bin
+ glp_get_num_int
+ glp_init_iocp
+ glp_intopt
+ glp_mip_col_val
+ glp_mip_obj_val
+ glp_mip_row_val
+ glp_mip_status
+ glp_set_col_kind
+;; from glpapi10 ;;
+ _glp_check_kkt
+;; from glpapi11 ;;
+ glp_print_ipt
+ glp_print_mip
+ glp_print_ranges
+ glp_print_sol
+ glp_read_ipt
+ glp_read_mip
+ glp_read_sol
+ glp_write_ipt
+ glp_write_mip
+ glp_write_sol
+;; from glpapi12 ;;
+ _glp_analyze_row
+ glp_analyze_bound
+ glp_analyze_coef
+ glp_bf_exists
+ glp_bf_updated
+ glp_btran
+ glp_dual_rtest
+ glp_eval_tab_col
+ glp_eval_tab_row
+ glp_factorize
+ glp_ftran
+ glp_get_bfcp
+ glp_get_bhead
+ glp_get_col_bind
+ glp_get_row_bind
+ glp_prim_rtest
+ glp_set_bfcp
+ glp_transform_col
+ glp_transform_row
+ glp_warm_up
+;; from glpapi13 ;;
+ glp_ios_add_row
+ glp_ios_best_node
+ glp_ios_branch_upon
+ glp_ios_can_branch
+ glp_ios_clear_pool
+ glp_ios_curr_node
+ glp_ios_del_row
+ glp_ios_get_prob
+ glp_ios_heur_sol
+ glp_ios_mip_gap
+ glp_ios_next_node
+ glp_ios_node_bound
+ glp_ios_node_data
+ glp_ios_node_level
+ glp_ios_pool_size
+ glp_ios_prev_node
+ glp_ios_reason
+ glp_ios_row_attr
+ glp_ios_select_node
+ glp_ios_terminate
+ glp_ios_tree_size
+ glp_ios_up_node
+;; from glpapi14 ;;
+ _glp_mpl_init_rand
+ glp_mpl_alloc_wksp
+ glp_mpl_build_prob
+ glp_mpl_free_wksp
+ glp_mpl_generate
+ glp_mpl_postsolve
+ glp_mpl_read_data
+ glp_mpl_read_model
+;; from glpapi15 ;;
+ glp_add_arc
+ glp_add_vertices
+ glp_create_graph
+ glp_create_v_index
+ glp_del_arc
+ glp_del_vertices
+ glp_delete_graph
+ glp_delete_v_index
+ glp_erase_graph
+ glp_find_vertex
+ glp_read_graph
+ glp_set_graph_name
+ glp_set_vertex_name
+ glp_write_graph
+;; from glpapi16 ;;
+ glp_strong_comp
+ glp_top_sort
+ glp_weak_comp
+;; from glpapi17 ;;
+ glp_asnprob_hall
+ glp_asnprob_lp
+ glp_asnprob_okalg
+ glp_check_asnprob
+ glp_cpp
+ glp_maxflow_ffalg
+ glp_maxflow_lp
+ glp_mincost_lp
+ glp_mincost_okalg
+;; from glpapi18 ;;
+ glp_wclique_exact
+;; from glpapi19 ;;
+ glp_minisat1
+;; from glpapi20 ;;
+ glp_intfeas1
+;; from glpapi21 ;;
+ glp_main
+;; from glpavl ;;
+ _glp_avl_create_tree
+ _glp_avl_delete_node
+ _glp_avl_delete_tree
+ _glp_avl_find_node
+ _glp_avl_get_node_link
+ _glp_avl_get_node_type
+ _glp_avl_insert_node
+ _glp_avl_set_node_link
+ _glp_avl_set_node_type
+ _glp_avl_strcmp
+;; from glpbfd ;;
+ _glp_bfd_btran
+ _glp_bfd_create_it
+ _glp_bfd_delete_it
+ _glp_bfd_factorize
+ _glp_bfd_ftran
+ _glp_bfd_get_count
+ _glp_bfd_set_parm
+ _glp_bfd_update_it
+;; from glpbfx ;;
+ _glp_bfx_btran
+ _glp_bfx_create_binv
+ _glp_bfx_delete_binv
+ _glp_bfx_factorize
+ _glp_bfx_ftran
+ _glp_bfx_update
+;; from glpcpx ;;
+ glp_init_cpxcp
+ glp_read_lp
+ glp_write_lp
+;; from glpdmp ;;
+ _glp_dmp_create_pool
+ _glp_dmp_delete_pool
+ _glp_dmp_free_atom
+ _glp_dmp_get_atom
+ _glp_dmp_in_use
+;; from glpdmx ;;
+ glp_check_cnfsat
+ glp_read_asnprob
+ glp_read_ccdata
+ glp_read_cnfsat
+ glp_read_maxflow
+ glp_read_mincost
+ glp_read_prob
+ glp_write_asnprob
+ glp_write_ccdata
+ glp_write_cnfsat
+ glp_write_maxflow
+ glp_write_mincost
+ glp_write_prob
+;; from glpenv01 ;;
+ _glp_get_env_ptr
+ glp_free_env
+ glp_init_env
+ glp_version
+;; from glpenv02 ;;
+ _glp_tls_get_ptr
+ _glp_tls_set_ptr
+;; from glpenv03 ;;
+ glp_close_tee
+ glp_open_tee
+ glp_printf
+ glp_term_hook
+ glp_term_out
+ glp_vprintf
+;; from glpenv04 ;;
+ glp_assert_
+ glp_error_
+ glp_error_hook
+;; from glpenv05 ;;
+ glp_calloc
+ glp_free
+ glp_malloc
+ glp_mem_limit
+ glp_mem_usage
+;; from glpenv06 ;;
+ glp_difftime
+ glp_time
+;; from glpenv07 ;;
+ _glp_lib_err_msg
+ _glp_lib_xerrmsg
+ _glp_lib_xfclose
+ _glp_lib_xfeof
+ _glp_lib_xferror
+ _glp_lib_xfflush
+ _glp_lib_xfgetc
+ _glp_lib_xfopen
+ _glp_lib_xfprintf
+ _glp_lib_xfputc
+;; from glpenv08 ;;
+ _glp_xdlclose
+ _glp_xdlopen
+ _glp_xdlsym
+;; from glpfhv ;;
+ _glp_fhv_btran
+ _glp_fhv_create_it
+ _glp_fhv_delete_it
+ _glp_fhv_factorize
+ _glp_fhv_ftran
+ _glp_fhv_h_solve
+ _glp_fhv_update_it
+;; from glpgmp ;;
+ _glp_gmp_free_atom
+ _glp_gmp_free_mem
+ _glp_gmp_get_atom
+ _glp_gmp_get_work
+ _glp_gmp_pool_count
+ _glp_mpq_abs
+ _glp_mpq_add
+ _glp_mpq_canonicalize
+ _glp_mpq_clear
+ _glp_mpq_cmp
+ _glp_mpq_div
+ _glp_mpq_get_d
+ _glp_mpq_init
+ _glp_mpq_mul
+ _glp_mpq_neg
+ _glp_mpq_out_str
+ _glp_mpq_set
+ _glp_mpq_set_d
+ _glp_mpq_set_si
+ _glp_mpq_sgn
+ _glp_mpq_sub
+ _glp_mpz_abs
+ _glp_mpz_add
+ _glp_mpz_clear
+ _glp_mpz_cmp
+ _glp_mpz_div
+ _glp_mpz_gcd
+ _glp_mpz_get_d
+ _glp_mpz_get_d_2exp
+ _glp_mpz_init
+ _glp_mpz_mul
+ _glp_mpz_neg
+ _glp_mpz_out_str
+ _glp_mpz_set
+ _glp_mpz_set_si
+ _glp_mpz_sgn
+ _glp_mpz_sub
+ _glp_mpz_swap
+;; from glphbm ;;
+ _glp_hbm_free_mat
+ _glp_hbm_read_mat
+;; from glpini01 ;;
+ glp_adv_basis
+;; from glpini02 ;;
+ glp_cpx_basis
+;; from glpios01 ;;
+ _glp_ios_add_row
+ _glp_ios_best_node
+ _glp_ios_clear_pool
+ _glp_ios_clone_node
+ _glp_ios_create_pool
+ _glp_ios_create_tree
+ _glp_ios_del_row
+ _glp_ios_delete_node
+ _glp_ios_delete_pool
+ _glp_ios_delete_tree
+ _glp_ios_eval_degrad
+ _glp_ios_find_row
+ _glp_ios_freeze_node
+ _glp_ios_is_hopeful
+ _glp_ios_relative_gap
+ _glp_ios_revive_node
+ _glp_ios_round_bound
+ _glp_ios_solve_node
+;; from glpios02 ;;
+ _glp_ios_preprocess_node
+;; from glpios03 ;;
+ _glp_ios_driver
+;; from glpios04 ;;
+ _glp_ios_check_vec
+ _glp_ios_clean_vec
+ _glp_ios_clear_vec
+ _glp_ios_copy_vec
+ _glp_ios_create_vec
+ _glp_ios_delete_vec
+ _glp_ios_get_vj
+ _glp_ios_linear_comb
+ _glp_ios_set_vj
+;; from glpios05 ;;
+ _glp_ios_gmi_gen
+;; from glpios06 ;;
+ _glp_ios_mir_gen
+ _glp_ios_mir_init
+ _glp_ios_mir_term
+;; from glpios07 ;;
+ _glp_ios_cov_gen
+;; from glpios08 ;;
+ _glp_ios_clq_gen
+ _glp_ios_clq_init
+ _glp_ios_clq_term
+;; from glpios09 ;;
+ _glp_ios_choose_var
+ _glp_ios_pcost_branch
+ _glp_ios_pcost_free
+ _glp_ios_pcost_init
+ _glp_ios_pcost_update
+;; from glpios10 ;;
+ _glp_ios_feas_pump
+;; from glpios11 ;;
+ _glp_ios_process_cuts
+;; from glpios12 ;;
+ _glp_ios_choose_node
+;; from glpipm ;;
+ _glp_ipm_solve
+;; from glplib01 ;;
+ _glp_lib_bigdiv
+ _glp_lib_bigmul
+;; from glplib02 ;;
+ _glp_lib_xladd
+ _glp_lib_xlcmp
+ _glp_lib_xldiv
+ _glp_lib_xlmul
+ _glp_lib_xlneg
+ _glp_lib_xlset
+ _glp_lib_xlsub
+ _glp_lib_xltoa
+ _glp_lib_xltod
+;; from glplib03 ;;
+ _glp_lib_fp2rat
+ _glp_lib_gcd
+ _glp_lib_gcdn
+ _glp_lib_jdate
+ _glp_lib_jday
+ _glp_lib_lcm
+ _glp_lib_lcmn
+ _glp_lib_round2n
+ _glp_lib_str2int
+ _glp_lib_str2num
+ _glp_lib_strrev
+ _glp_lib_strspx
+ _glp_lib_strtrim
+;; from glplpf ;;
+ _glp_lpf_btran
+ _glp_lpf_create_it
+ _glp_lpf_delete_it
+ _glp_lpf_factorize
+ _glp_lpf_ftran
+ _glp_lpf_update_it
+;; from glplpx01 ;;
+ _glp_lpx_add_cols
+ _glp_lpx_add_rows
+ _glp_lpx_adv_basis
+ _glp_lpx_check_int
+ _glp_lpx_check_kkt
+ _glp_lpx_cpx_basis
+ _glp_lpx_create_index
+ _glp_lpx_create_prob
+ _glp_lpx_del_cols
+ _glp_lpx_del_rows
+ _glp_lpx_delete_index
+ _glp_lpx_delete_prob
+ _glp_lpx_dual_ratio_test
+ _glp_lpx_eval_tab_col
+ _glp_lpx_eval_tab_row
+ _glp_lpx_exact
+ _glp_lpx_find_col
+ _glp_lpx_find_row
+ _glp_lpx_get_class
+ _glp_lpx_get_col_bnds
+ _glp_lpx_get_col_dual
+ _glp_lpx_get_col_info
+ _glp_lpx_get_col_kind
+ _glp_lpx_get_col_lb
+ _glp_lpx_get_col_name
+ _glp_lpx_get_col_prim
+ _glp_lpx_get_col_stat
+ _glp_lpx_get_col_type
+ _glp_lpx_get_col_ub
+ _glp_lpx_get_dual_stat
+ _glp_lpx_get_int_parm
+ _glp_lpx_get_mat_col
+ _glp_lpx_get_mat_row
+ _glp_lpx_get_num_bin
+ _glp_lpx_get_num_cols
+ _glp_lpx_get_num_int
+ _glp_lpx_get_num_nz
+ _glp_lpx_get_num_rows
+ _glp_lpx_get_obj_coef
+ _glp_lpx_get_obj_dir
+ _glp_lpx_get_obj_name
+ _glp_lpx_get_obj_val
+ _glp_lpx_get_prim_stat
+ _glp_lpx_get_prob_name
+ _glp_lpx_get_ray_info
+ _glp_lpx_get_real_parm
+ _glp_lpx_get_row_bnds
+ _glp_lpx_get_row_dual
+ _glp_lpx_get_row_info
+ _glp_lpx_get_row_lb
+ _glp_lpx_get_row_name
+ _glp_lpx_get_row_prim
+ _glp_lpx_get_row_stat
+ _glp_lpx_get_row_type
+ _glp_lpx_get_row_ub
+ _glp_lpx_get_status
+ _glp_lpx_integer
+ _glp_lpx_interior
+ _glp_lpx_intopt
+ _glp_lpx_ipt_col_dual
+ _glp_lpx_ipt_col_prim
+ _glp_lpx_ipt_obj_val
+ _glp_lpx_ipt_row_dual
+ _glp_lpx_ipt_row_prim
+ _glp_lpx_ipt_status
+ _glp_lpx_is_b_avail
+ _glp_lpx_load_matrix
+ _glp_lpx_main
+ _glp_lpx_mip_col_val
+ _glp_lpx_mip_obj_val
+ _glp_lpx_mip_row_val
+ _glp_lpx_mip_status
+ _glp_lpx_prim_ratio_test
+ _glp_lpx_print_ips
+ _glp_lpx_print_mip
+ _glp_lpx_print_prob
+ _glp_lpx_print_sens_bnds
+ _glp_lpx_print_sol
+ _glp_lpx_read_bas
+ _glp_lpx_read_cpxlp
+ _glp_lpx_read_freemps
+ _glp_lpx_read_model
+ _glp_lpx_read_mps
+ _glp_lpx_reset_parms
+ _glp_lpx_scale_prob
+ _glp_lpx_set_class
+ _glp_lpx_set_col_bnds
+ _glp_lpx_set_col_kind
+ _glp_lpx_set_col_name
+ _glp_lpx_set_col_stat
+ _glp_lpx_set_int_parm
+ _glp_lpx_set_mat_col
+ _glp_lpx_set_mat_row
+ _glp_lpx_set_obj_coef
+ _glp_lpx_set_obj_dir
+ _glp_lpx_set_obj_name
+ _glp_lpx_set_prob_name
+ _glp_lpx_set_real_parm
+ _glp_lpx_set_row_bnds
+ _glp_lpx_set_row_name
+ _glp_lpx_set_row_stat
+ _glp_lpx_simplex
+ _glp_lpx_std_basis
+ _glp_lpx_transform_col
+ _glp_lpx_transform_row
+ _glp_lpx_unscale_prob
+ _glp_lpx_warm_up
+ _glp_lpx_write_bas
+ _glp_lpx_write_cpxlp
+ _glp_lpx_write_freemps
+ _glp_lpx_write_mps
+;; from glplpx02 ;;
+ _glp_put_mip_soln
+ _glp_put_solution
+;; from glplpx03 ;;
+ _glp_lpx_write_pb
+;; from glpluf ;;
+ _glp_luf_a_solve
+ _glp_luf_create_it
+ _glp_luf_defrag_sva
+ _glp_luf_delete_it
+ _glp_luf_enlarge_col
+ _glp_luf_enlarge_row
+ _glp_luf_f_solve
+ _glp_luf_factorize
+ _glp_luf_v_solve
+;; from glplux ;;
+ _glp_lux_create
+ _glp_lux_decomp
+ _glp_lux_delete
+ _glp_lux_f_solve
+ _glp_lux_solve
+ _glp_lux_v_solve
+;; from glpmat ;;
+ _glp_mat_adat_numeric
+ _glp_mat_adat_symbolic
+ _glp_mat_amd_order1
+ _glp_mat_check_fvs
+ _glp_mat_check_pattern
+ _glp_mat_chol_numeric
+ _glp_mat_chol_symbolic
+ _glp_mat_min_degree
+ _glp_mat_symamd_ord
+ _glp_mat_transpose
+ _glp_mat_u_solve
+ _glp_mat_ut_solve
+;; from glpmpl01 ;;
+ _glp_mpl_append_block
+ _glp_mpl_append_char
+ _glp_mpl_append_slot
+ _glp_mpl_arg_list_len
+ _glp_mpl_branched_expression
+ _glp_mpl_check_statement
+ _glp_mpl_close_scope
+ _glp_mpl_constraint_statement
+ _glp_mpl_create_arg_list
+ _glp_mpl_create_block
+ _glp_mpl_create_domain
+ _glp_mpl_display_statement
+ _glp_mpl_domain_arity
+ _glp_mpl_elemset_argument
+ _glp_mpl_end_statement
+ _glp_mpl_enter_context
+ _glp_mpl_error_dimension
+ _glp_mpl_error_following
+ _glp_mpl_error_preceding
+ _glp_mpl_expand_arg_list
+ _glp_mpl_expression_0
+ _glp_mpl_expression_1
+ _glp_mpl_expression_10
+ _glp_mpl_expression_11
+ _glp_mpl_expression_12
+ _glp_mpl_expression_13
+ _glp_mpl_expression_2
+ _glp_mpl_expression_3
+ _glp_mpl_expression_4
+ _glp_mpl_expression_5
+ _glp_mpl_expression_6
+ _glp_mpl_expression_7
+ _glp_mpl_expression_8
+ _glp_mpl_expression_9
+ _glp_mpl_expression_list
+ _glp_mpl_for_statement
+ _glp_mpl_function_reference
+ _glp_mpl_get_char
+ _glp_mpl_get_token
+ _glp_mpl_indexing_expression
+ _glp_mpl_is_keyword
+ _glp_mpl_is_reserved
+ _glp_mpl_iterated_expression
+ _glp_mpl_literal_set
+ _glp_mpl_make_binary
+ _glp_mpl_make_code
+ _glp_mpl_make_ternary
+ _glp_mpl_make_unary
+ _glp_mpl_model_section
+ _glp_mpl_numeric_argument
+ _glp_mpl_numeric_literal
+ _glp_mpl_object_reference
+ _glp_mpl_objective_statement
+ _glp_mpl_parameter_statement
+ _glp_mpl_primary_expression
+ _glp_mpl_print_context
+ _glp_mpl_printf_statement
+ _glp_mpl_set_expression
+ _glp_mpl_set_statement
+ _glp_mpl_simple_statement
+ _glp_mpl_solve_statement
+ _glp_mpl_string_literal
+ _glp_mpl_subscript_list
+ _glp_mpl_symbolic_argument
+ _glp_mpl_table_statement
+ _glp_mpl_unget_token
+ _glp_mpl_variable_statement
+;; from glpmpl02 ;;
+ _glp_mpl_create_slice
+ _glp_mpl_data_section
+ _glp_mpl_delete_slice
+ _glp_mpl_expand_slice
+ _glp_mpl_fake_slice
+ _glp_mpl_is_literal
+ _glp_mpl_is_number
+ _glp_mpl_is_symbol
+ _glp_mpl_matrix_format
+ _glp_mpl_parameter_data
+ _glp_mpl_plain_format
+ _glp_mpl_read_number
+ _glp_mpl_read_slice
+ _glp_mpl_read_symbol
+ _glp_mpl_read_value
+ _glp_mpl_select_parameter
+ _glp_mpl_select_set
+ _glp_mpl_set_data
+ _glp_mpl_set_default
+ _glp_mpl_simple_format
+ _glp_mpl_slice_arity
+ _glp_mpl_slice_dimen
+ _glp_mpl_tabbing_format
+ _glp_mpl_tabular_format
+;; from glpmpl03 ;;
+ _glp_mpl_add_member
+ _glp_mpl_add_tuple
+ _glp_mpl_arelset_member
+ _glp_mpl_arelset_size
+ _glp_mpl_assign_dummy_index
+ _glp_mpl_build_subtuple
+ _glp_mpl_check_elem_set
+ _glp_mpl_check_then_add
+ _glp_mpl_check_value_num
+ _glp_mpl_check_value_sym
+ _glp_mpl_clean_check
+ _glp_mpl_clean_code
+ _glp_mpl_clean_constraint
+ _glp_mpl_clean_display
+ _glp_mpl_clean_domain
+ _glp_mpl_clean_for
+ _glp_mpl_clean_parameter
+ _glp_mpl_clean_printf
+ _glp_mpl_clean_set
+ _glp_mpl_clean_statement
+ _glp_mpl_clean_table
+ _glp_mpl_clean_variable
+ _glp_mpl_compare_strings
+ _glp_mpl_compare_symbols
+ _glp_mpl_compare_tuples
+ _glp_mpl_concat_symbols
+ _glp_mpl_constant_term
+ _glp_mpl_copy_elemset
+ _glp_mpl_copy_formula
+ _glp_mpl_copy_string
+ _glp_mpl_copy_symbol
+ _glp_mpl_copy_tuple
+ _glp_mpl_create_arelset
+ _glp_mpl_create_array
+ _glp_mpl_create_elemset
+ _glp_mpl_create_string
+ _glp_mpl_create_symbol_num
+ _glp_mpl_create_symbol_str
+ _glp_mpl_create_tuple
+ _glp_mpl_delete_array
+ _glp_mpl_delete_elemset
+ _glp_mpl_delete_formula
+ _glp_mpl_delete_string
+ _glp_mpl_delete_symbol
+ _glp_mpl_delete_tuple
+ _glp_mpl_delete_value
+ _glp_mpl_enter_domain_block
+ _glp_mpl_eval_elemset
+ _glp_mpl_eval_formula
+ _glp_mpl_eval_logical
+ _glp_mpl_eval_member_con
+ _glp_mpl_eval_member_num
+ _glp_mpl_eval_member_set
+ _glp_mpl_eval_member_sym
+ _glp_mpl_eval_member_var
+ _glp_mpl_eval_numeric
+ _glp_mpl_eval_symbolic
+ _glp_mpl_eval_tuple
+ _glp_mpl_eval_whole_con
+ _glp_mpl_eval_whole_par
+ _glp_mpl_eval_whole_set
+ _glp_mpl_eval_whole_var
+ _glp_mpl_eval_within_domain
+ _glp_mpl_execute_check
+ _glp_mpl_execute_display
+ _glp_mpl_execute_for
+ _glp_mpl_execute_printf
+ _glp_mpl_execute_statement
+ _glp_mpl_execute_table
+ _glp_mpl_expand_tuple
+ _glp_mpl_fetch_string
+ _glp_mpl_find_member
+ _glp_mpl_find_tuple
+ _glp_mpl_format_symbol
+ _glp_mpl_format_tuple
+ _glp_mpl_fp_add
+ _glp_mpl_fp_atan
+ _glp_mpl_fp_atan2
+ _glp_mpl_fp_cos
+ _glp_mpl_fp_div
+ _glp_mpl_fp_exp
+ _glp_mpl_fp_idiv
+ _glp_mpl_fp_irand224
+ _glp_mpl_fp_less
+ _glp_mpl_fp_log
+ _glp_mpl_fp_log10
+ _glp_mpl_fp_mod
+ _glp_mpl_fp_mul
+ _glp_mpl_fp_normal
+ _glp_mpl_fp_normal01
+ _glp_mpl_fp_power
+ _glp_mpl_fp_round
+ _glp_mpl_fp_sin
+ _glp_mpl_fp_sqrt
+ _glp_mpl_fp_sub
+ _glp_mpl_fp_trunc
+ _glp_mpl_fp_uniform01
+ _glp_mpl_free_dca
+ _glp_mpl_get_domain_tuple
+ _glp_mpl_is_member
+ _glp_mpl_linear_comb
+ _glp_mpl_loop_within_domain
+ _glp_mpl_out_of_domain
+ _glp_mpl_reduce_terms
+ _glp_mpl_remove_constant
+ _glp_mpl_set_cross
+ _glp_mpl_set_diff
+ _glp_mpl_set_inter
+ _glp_mpl_set_symdiff
+ _glp_mpl_set_union
+ _glp_mpl_single_variable
+ _glp_mpl_tab_get_arg
+ _glp_mpl_tab_get_name
+ _glp_mpl_tab_get_num
+ _glp_mpl_tab_get_str
+ _glp_mpl_tab_get_type
+ _glp_mpl_tab_num_args
+ _glp_mpl_tab_num_flds
+ _glp_mpl_tab_set_num
+ _glp_mpl_tab_set_str
+ _glp_mpl_take_member_con
+ _glp_mpl_take_member_num
+ _glp_mpl_take_member_set
+ _glp_mpl_take_member_sym
+ _glp_mpl_take_member_var
+ _glp_mpl_tuple_dimen
+ _glp_mpl_uniform
+ _glp_mpl_update_dummy_indices
+;; from glpmpl04 ;;
+ _glp_mpl_alloc_content
+ _glp_mpl_build_problem
+ _glp_mpl_clean_model
+ _glp_mpl_close_input
+ _glp_mpl_error
+ _glp_mpl_flush_output
+ _glp_mpl_generate
+ _glp_mpl_generate_model
+ _glp_mpl_get_col_bnds
+ _glp_mpl_get_col_kind
+ _glp_mpl_get_col_name
+ _glp_mpl_get_mat_row
+ _glp_mpl_get_num_cols
+ _glp_mpl_get_num_rows
+ _glp_mpl_get_prob_name
+ _glp_mpl_get_row_bnds
+ _glp_mpl_get_row_c0
+ _glp_mpl_get_row_kind
+ _glp_mpl_get_row_name
+ _glp_mpl_has_solve_stmt
+ _glp_mpl_initialize
+ _glp_mpl_open_input
+ _glp_mpl_open_output
+ _glp_mpl_postsolve
+ _glp_mpl_postsolve_model
+ _glp_mpl_put_col_soln
+ _glp_mpl_put_row_soln
+ _glp_mpl_read_char
+ _glp_mpl_read_data
+ _glp_mpl_read_model
+ _glp_mpl_terminate
+ _glp_mpl_warning
+ _glp_mpl_write_char
+ _glp_mpl_write_text
+;; from glpmpl05 ;;
+ _glp_mpl_fn_gmtime
+ _glp_mpl_fn_str2time
+ _glp_mpl_fn_time2str
+;; from glpmpl06 ;;
+ _glp_mpl_tab_drv_close
+ _glp_mpl_tab_drv_open
+ _glp_mpl_tab_drv_read
+ _glp_mpl_tab_drv_write
+;; from glpmps ;;
+ glp_init_mpscp
+ glp_read_mps
+ glp_write_mps
+;; from glpnet01 ;;
+ _glp_mc21a
+;; from glpnet02 ;;
+ _glp_mc13d
+;; from glpnet03 ;;
+ glp_netgen
+;; from glpnet04 ;;
+ glp_gridgen
+;; from glpnet05 ;;
+ glp_rmfgen
+;; from glpnet06 ;;
+ _glp_okalg
+;; from glpnet07 ;;
+ _glp_ffalg
+;; from glpnet08 ;;
+ _glp_wclique
+;; from glpnet09 ;;
+ _glp_kellerman
+;; from glpnpp01 ;;
+ _glp_npp_activate_col
+ _glp_npp_activate_row
+ _glp_npp_add_aij
+ _glp_npp_add_col
+ _glp_npp_add_row
+ _glp_npp_build_prob
+ _glp_npp_col_nnz
+ _glp_npp_create_wksp
+ _glp_npp_deactivate_col
+ _glp_npp_deactivate_row
+ _glp_npp_del_aij
+ _glp_npp_del_col
+ _glp_npp_del_row
+ _glp_npp_delete_wksp
+ _glp_npp_erase_row
+ _glp_npp_insert_col
+ _glp_npp_insert_row
+ _glp_npp_load_prob
+ _glp_npp_postprocess
+ _glp_npp_push_tse
+ _glp_npp_remove_col
+ _glp_npp_remove_row
+ _glp_npp_row_nnz
+ _glp_npp_unload_sol
+;; from glpnpp02 ;;
+ _glp_npp_dbnd_col
+ _glp_npp_fixed_col
+ _glp_npp_free_col
+ _glp_npp_free_row
+ _glp_npp_geq_row
+ _glp_npp_lbnd_col
+ _glp_npp_leq_row
+ _glp_npp_make_equality
+ _glp_npp_make_fixed
+ _glp_npp_ubnd_col
+;; from glpnpp03 ;;
+ _glp_npp_analyze_row
+ _glp_npp_empty_col
+ _glp_npp_empty_row
+ _glp_npp_eq_doublet
+ _glp_npp_eq_singlet
+ _glp_npp_forcing_row
+ _glp_npp_implied_bounds
+ _glp_npp_implied_free
+ _glp_npp_implied_lower
+ _glp_npp_implied_slack
+ _glp_npp_implied_upper
+ _glp_npp_implied_value
+ _glp_npp_inactive_bound
+ _glp_npp_ineq_singlet
+;; from glpnpp04 ;;
+ _glp_npp_binarize_prob
+ _glp_npp_hidden_covering
+ _glp_npp_hidden_packing
+ _glp_npp_implied_packing
+ _glp_npp_is_covering
+ _glp_npp_is_packing
+ _glp_npp_is_partitioning
+ _glp_npp_reduce_ineq_coef
+;; from glpnpp05 ;;
+ _glp_npp_clean_prob
+ _glp_npp_improve_bounds
+ _glp_npp_integer
+ _glp_npp_process_col
+ _glp_npp_process_prob
+ _glp_npp_process_row
+ _glp_npp_simplex
+;; from glpnpp06 ;;
+ _glp_npp_sat_encode_clause
+ _glp_npp_sat_encode_geq
+ _glp_npp_sat_encode_leq
+ _glp_npp_sat_encode_pack
+ _glp_npp_sat_encode_prob
+ _glp_npp_sat_encode_row
+ _glp_npp_sat_encode_sum2
+ _glp_npp_sat_encode_sum3
+ _glp_npp_sat_encode_sum_ax
+ _glp_npp_sat_fixed_col
+ _glp_npp_sat_free_row
+ _glp_npp_sat_is_bin_comb
+ _glp_npp_sat_is_cover_ineq
+ _glp_npp_sat_is_pack_ineq
+ _glp_npp_sat_is_partn_eq
+ _glp_npp_sat_normalize_clause
+ _glp_npp_sat_num_neg_coef
+ _glp_npp_sat_num_pos_coef
+ _glp_npp_sat_reverse_row
+ _glp_npp_sat_split_pack
+;; from glpqmd ;;
+ _glp_qmd_genqmd
+ _glp_qmd_qmdmrg
+ _glp_qmd_qmdqt
+ _glp_qmd_qmdrch
+ _glp_qmd_qmdupd
+;; from glprgr ;;
+ _glp_rgr_write_bmp16
+;; from glprng01 ;;
+ _glp_rng_create_rand
+ _glp_rng_delete_rand
+ _glp_rng_init_rand
+ _glp_rng_next_rand
+ _glp_rng_unif_rand
+;; from glprng02 ;;
+ _glp_rng_unif_01
+ _glp_rng_uniform
+;; from glpscf ;;
+ _glp_scf_create_it
+ _glp_scf_delete_it
+ _glp_scf_reset_it
+ _glp_scf_solve_it
+ _glp_scf_update_exp
+;; from glpscl ;;
+ glp_scale_prob
+;; from glpsdf ;;
+ glp_sdf_close_file
+ glp_sdf_error
+ glp_sdf_line
+ glp_sdf_open_file
+ glp_sdf_read_int
+ glp_sdf_read_item
+ glp_sdf_read_num
+ glp_sdf_read_text
+ glp_sdf_set_jump
+ glp_sdf_warning
+;; from glpspm ;;
+ _glp_spm_add_mat
+ _glp_spm_add_num
+ _glp_spm_add_sym
+ _glp_spm_check_per
+ _glp_spm_count_nnz
+ _glp_spm_create_mat
+ _glp_spm_create_per
+ _glp_spm_delete_mat
+ _glp_spm_delete_per
+ _glp_spm_drop_zeros
+ _glp_spm_mul_mat
+ _glp_spm_mul_num
+ _glp_spm_mul_sym
+ _glp_spm_new_elem
+ _glp_spm_read_hbm
+ _glp_spm_read_mat
+ _glp_spm_show_mat
+ _glp_spm_test_mat_d
+ _glp_spm_test_mat_e
+ _glp_spm_transpose
+ _glp_spm_write_mat
+;; from glpspx01 ;;
+ _glp_spx_primal
+;; from glpspx02 ;;
+ _glp_spx_dual
+;; from glpsql ;;
+ _glp_db_iodbc_close
+ _glp_db_iodbc_open
+ _glp_db_iodbc_read
+ _glp_db_iodbc_write
+ _glp_db_mysql_close
+ _glp_db_mysql_open
+ _glp_db_mysql_read
+ _glp_db_mysql_write
+;; from glpssx01 ;;
+ _glp_ssx_change_basis
+ _glp_ssx_chuzc
+ _glp_ssx_chuzr
+ _glp_ssx_create
+ _glp_ssx_delete
+ _glp_ssx_eval_bbar
+ _glp_ssx_eval_cbar
+ _glp_ssx_eval_col
+ _glp_ssx_eval_dj
+ _glp_ssx_eval_pi
+ _glp_ssx_eval_rho
+ _glp_ssx_eval_row
+ _glp_ssx_factorize
+ _glp_ssx_get_xNj
+ _glp_ssx_update_bbar
+ _glp_ssx_update_cbar
+ _glp_ssx_update_pi
+;; from glpssx02 ;;
+ _glp_ssx_driver
+ _glp_ssx_phase_I
+ _glp_ssx_phase_II
+;; from glptsp ;;
+ _glp_tsp_distance
+ _glp_tsp_free_data
+ _glp_tsp_read_data
+;; from gzclose ;;
+ _glp_zlib_gzclose
+;; from gzlib ;;
+ _glp_zlib_gz_error
+ _glp_zlib_gzbuffer
+ _glp_zlib_gzclearerr
+ _glp_zlib_gzdopen
+ _glp_zlib_gzeof
+ _glp_zlib_gzerror
+ _glp_zlib_gzoffset
+ _glp_zlib_gzoffset64
+ _glp_zlib_gzopen
+ _glp_zlib_gzopen64
+ _glp_zlib_gzrewind
+ _glp_zlib_gzseek
+ _glp_zlib_gzseek64
+ _glp_zlib_gztell
+ _glp_zlib_gztell64
+;; from gzread ;;
+ _glp_zlib_gzclose_r
+ _glp_zlib_gzdirect
+ _glp_zlib_gzgetc
+ _glp_zlib_gzgets
+ _glp_zlib_gzread
+ _glp_zlib_gzungetc
+;; from gzwrite ;;
+ _glp_zlib_gzclose_w
+ _glp_zlib_gzflush
+ _glp_zlib_gzprintf
+ _glp_zlib_gzputc
+ _glp_zlib_gzputs
+ _glp_zlib_gzsetparams
+ _glp_zlib_gzwrite
+;; from infback ;;
+ _glp_zlib_inflateBack
+ _glp_zlib_inflateBackEnd
+ _glp_zlib_inflateBackInit_
+;; from inffast ;;
+ _glp_zlib_inflate_fast
+;; from inflate ;;
+ _glp_zlib_inflate
+ _glp_zlib_inflateCopy
+ _glp_zlib_inflateEnd
+ _glp_zlib_inflateGetHeader
+ _glp_zlib_inflateInit2_
+ _glp_zlib_inflateInit_
+ _glp_zlib_inflateMark
+ _glp_zlib_inflatePrime
+ _glp_zlib_inflateReset
+ _glp_zlib_inflateReset2
+ _glp_zlib_inflateSetDictionary
+ _glp_zlib_inflateSync
+ _glp_zlib_inflateSyncPoint
+ _glp_zlib_inflateUndermine
+;; from inftrees ;;
+ _glp_zlib_inflate_copyright
+ _glp_zlib_inflate_table
+;; from minisat ;;
+ _glp_minisat_addclause
+ _glp_minisat_delete
+ _glp_minisat_nclauses
+ _glp_minisat_nconflicts
+ _glp_minisat_new
+ _glp_minisat_nvars
+ _glp_minisat_propagate
+ _glp_minisat_reducedb
+ _glp_minisat_setnvars
+ _glp_minisat_simplify
+ _glp_minisat_solve
+;; from trees ;;
+ _glp_zlib_dist_code
+ _glp_zlib_length_code
+ _glp_zlib_tr_align
+ _glp_zlib_tr_flush_block
+ _glp_zlib_tr_init
+ _glp_zlib_tr_stored_block
+ _glp_zlib_tr_tally
+;; from uncompr ;;
+ _glp_zlib_uncompress
+;; from zio ;;
+ _glp_zlib_close
+ _glp_zlib_lseek
+ _glp_zlib_open
+ _glp_zlib_read
+ _glp_zlib_write
+;; from zutil ;;
+ _glp_zlib_zError
+ _glp_zlib_z_errmsg
+ _glp_zlib_zcalloc
+ _glp_zlib_zcfree
+ _glp_zlib_zlibCompileFlags
+ _glp_zlib_zlibVersion
Index: deps/glpk/w64/makefile_VC
===================================================================
--- deps/glpk/w64/makefile_VC	(revision 9)
+++ deps/glpk/w64/makefile_VC	(revision 9)
@@ -0,0 +1,168 @@
+## Build GLPK with Microsoft Visual Studio Express ##
+
+CFLAGS = \
+/I. \
+/I..\src \
+/I..\src\amd \
+/I..\src\colamd \
+/I..\src\minisat \
+/I..\src\zlib \
+/DHAVE_CONFIG_H=1 \
+/D_CRT_SECURE_NO_WARNINGS=1 \
+/nologo \
+/W3 \
+/O2
+
+OBJSET = \
+..\src\glpapi01.obj \
+..\src\glpapi02.obj \
+..\src\glpapi03.obj \
+..\src\glpapi04.obj \
+..\src\glpapi05.obj \
+..\src\glpapi06.obj \
+..\src\glpapi07.obj \
+..\src\glpapi08.obj \
+..\src\glpapi09.obj \
+..\src\glpapi10.obj \
+..\src\glpapi11.obj \
+..\src\glpapi12.obj \
+..\src\glpapi13.obj \
+..\src\glpapi14.obj \
+..\src\glpapi15.obj \
+..\src\glpapi16.obj \
+..\src\glpapi17.obj \
+..\src\glpapi18.obj \
+..\src\glpapi19.obj \
+..\src\glpapi20.obj \
+..\src\glpapi21.obj \
+..\src\glpavl.obj \
+..\src\glpbfd.obj \
+..\src\glpbfx.obj \
+..\src\glpcpx.obj \
+..\src\glpdmp.obj \
+..\src\glpdmx.obj \
+..\src\glpenv01.obj \
+..\src\glpenv02.obj \
+..\src\glpenv03.obj \
+..\src\glpenv04.obj \
+..\src\glpenv05.obj \
+..\src\glpenv06.obj \
+..\src\glpenv07.obj \
+..\src\glpenv08.obj \
+..\src\glpfhv.obj \
+..\src\glpgmp.obj \
+..\src\glphbm.obj \
+..\src\glpini01.obj \
+..\src\glpini02.obj \
+..\src\glpios01.obj \
+..\src\glpios02.obj \
+..\src\glpios03.obj \
+..\src\glpios04.obj \
+..\src\glpios05.obj \
+..\src\glpios06.obj \
+..\src\glpios07.obj \
+..\src\glpios08.obj \
+..\src\glpios09.obj \
+..\src\glpios10.obj \
+..\src\glpios11.obj \
+..\src\glpios12.obj \
+..\src\glpipm.obj \
+..\src\glplib01.obj \
+..\src\glplib02.obj \
+..\src\glplib03.obj \
+..\src\glplpf.obj \
+..\src\glplpx01.obj \
+..\src\glplpx02.obj \
+..\src\glplpx03.obj \
+..\src\glpluf.obj \
+..\src\glplux.obj \
+..\src\glpmat.obj \
+..\src\glpmpl01.obj \
+..\src\glpmpl02.obj \
+..\src\glpmpl03.obj \
+..\src\glpmpl04.obj \
+..\src\glpmpl05.obj \
+..\src\glpmpl06.obj \
+..\src\glpmps.obj \
+..\src\glpnet01.obj \
+..\src\glpnet02.obj \
+..\src\glpnet03.obj \
+..\src\glpnet04.obj \
+..\src\glpnet05.obj \
+..\src\glpnet06.obj \
+..\src\glpnet07.obj \
+..\src\glpnet08.obj \
+..\src\glpnet09.obj \
+..\src\glpnpp01.obj \
+..\src\glpnpp02.obj \
+..\src\glpnpp03.obj \
+..\src\glpnpp04.obj \
+..\src\glpnpp05.obj \
+..\src\glpnpp06.obj \
+..\src\glpqmd.obj \
+..\src\glprgr.obj \
+..\src\glprng01.obj \
+..\src\glprng02.obj \
+..\src\glpscf.obj \
+..\src\glpscl.obj \
+..\src\glpsdf.obj \
+..\src\glpspm.obj \
+..\src\glpspx01.obj \
+..\src\glpspx02.obj \
+..\src\glpsql.obj \
+..\src\glpssx01.obj \
+..\src\glpssx02.obj \
+..\src\glptsp.obj \
+..\src\amd\amd_1.obj \
+..\src\amd\amd_2.obj \
+..\src\amd\amd_aat.obj \
+..\src\amd\amd_control.obj \
+..\src\amd\amd_defaults.obj \
+..\src\amd\amd_dump.obj \
+..\src\amd\amd_info.obj \
+..\src\amd\amd_order.obj \
+..\src\amd\amd_post_tree.obj \
+..\src\amd\amd_postorder.obj \
+..\src\amd\amd_preprocess.obj \
+..\src\amd\amd_valid.obj \
+..\src\colamd\colamd.obj \
+..\src\minisat\minisat.obj \
+..\src\zlib\adler32.obj \
+..\src\zlib\compress.obj \
+..\src\zlib\crc32.obj \
+..\src\zlib\deflate.obj \
+..\src\zlib\gzclose.obj \
+..\src\zlib\gzlib.obj \
+..\src\zlib\gzread.obj \
+..\src\zlib\gzwrite.obj \
+..\src\zlib\infback.obj \
+..\src\zlib\inffast.obj \
+..\src\zlib\inflate.obj \
+..\src\zlib\inftrees.obj \
+..\src\zlib\trees.obj \
+..\src\zlib\uncompr.obj \
+..\src\zlib\zio.obj \
+..\src\zlib\zutil.obj
+
+.c.obj:
+        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
+
+all: glpk.lib glpsol.exe
+
+glpk.lib: $(OBJSET)
+        lib.exe /out:glpk.lib \
+                ..\src\*.obj \
+                ..\src\amd\*.obj \
+                ..\src\colamd\*.obj \
+                ..\src\minisat\*.obj \
+                ..\src\zlib\*.obj
+
+glpsol.exe: ..\examples\glpsol.obj glpk.lib
+        cl.exe $(CFLAGS) /Feglpsol.exe \
+                ..\examples\glpsol.obj glpk.lib
+
+check: glpsol.exe
+        .\glpsol.exe --version
+        .\glpsol.exe --mps ..\examples\plan.mps
+
+## eof ##
Index: deps/glpk/w64/makefile_VC_DLL
===================================================================
--- deps/glpk/w64/makefile_VC_DLL	(revision 9)
+++ deps/glpk/w64/makefile_VC_DLL	(revision 9)
@@ -0,0 +1,169 @@
+## Build GLPK DLL with Microsoft Visual Studio Express ##
+
+CFLAGS = \
+/I. \
+/I..\src \
+/I..\src\amd \
+/I..\src\colamd \
+/I..\src\minisat \
+/I..\src\zlib \
+/DHAVE_CONFIG_H=1 \
+/D_CRT_SECURE_NO_WARNINGS=1 \
+/nologo \
+/W3 \
+/O2
+
+OBJSET = \
+..\src\glpapi01.obj \
+..\src\glpapi02.obj \
+..\src\glpapi03.obj \
+..\src\glpapi04.obj \
+..\src\glpapi05.obj \
+..\src\glpapi06.obj \
+..\src\glpapi07.obj \
+..\src\glpapi08.obj \
+..\src\glpapi09.obj \
+..\src\glpapi10.obj \
+..\src\glpapi11.obj \
+..\src\glpapi12.obj \
+..\src\glpapi13.obj \
+..\src\glpapi14.obj \
+..\src\glpapi15.obj \
+..\src\glpapi16.obj \
+..\src\glpapi17.obj \
+..\src\glpapi18.obj \
+..\src\glpapi19.obj \
+..\src\glpapi20.obj \
+..\src\glpapi21.obj \
+..\src\glpavl.obj \
+..\src\glpbfd.obj \
+..\src\glpbfx.obj \
+..\src\glpcpx.obj \
+..\src\glpdmp.obj \
+..\src\glpdmx.obj \
+..\src\glpenv01.obj \
+..\src\glpenv02.obj \
+..\src\glpenv03.obj \
+..\src\glpenv04.obj \
+..\src\glpenv05.obj \
+..\src\glpenv06.obj \
+..\src\glpenv07.obj \
+..\src\glpenv08.obj \
+..\src\glpfhv.obj \
+..\src\glpgmp.obj \
+..\src\glphbm.obj \
+..\src\glpini01.obj \
+..\src\glpini02.obj \
+..\src\glpios01.obj \
+..\src\glpios02.obj \
+..\src\glpios03.obj \
+..\src\glpios04.obj \
+..\src\glpios05.obj \
+..\src\glpios06.obj \
+..\src\glpios07.obj \
+..\src\glpios08.obj \
+..\src\glpios09.obj \
+..\src\glpios10.obj \
+..\src\glpios11.obj \
+..\src\glpios12.obj \
+..\src\glpipm.obj \
+..\src\glplib01.obj \
+..\src\glplib02.obj \
+..\src\glplib03.obj \
+..\src\glplpf.obj \
+..\src\glplpx01.obj \
+..\src\glplpx02.obj \
+..\src\glplpx03.obj \
+..\src\glpluf.obj \
+..\src\glplux.obj \
+..\src\glpmat.obj \
+..\src\glpmpl01.obj \
+..\src\glpmpl02.obj \
+..\src\glpmpl03.obj \
+..\src\glpmpl04.obj \
+..\src\glpmpl05.obj \
+..\src\glpmpl06.obj \
+..\src\glpmps.obj \
+..\src\glpnet01.obj \
+..\src\glpnet02.obj \
+..\src\glpnet03.obj \
+..\src\glpnet04.obj \
+..\src\glpnet05.obj \
+..\src\glpnet06.obj \
+..\src\glpnet07.obj \
+..\src\glpnet08.obj \
+..\src\glpnet09.obj \
+..\src\glpnpp01.obj \
+..\src\glpnpp02.obj \
+..\src\glpnpp03.obj \
+..\src\glpnpp04.obj \
+..\src\glpnpp05.obj \
+..\src\glpnpp06.obj \
+..\src\glpqmd.obj \
+..\src\glprgr.obj \
+..\src\glprng01.obj \
+..\src\glprng02.obj \
+..\src\glpscf.obj \
+..\src\glpscl.obj \
+..\src\glpsdf.obj \
+..\src\glpspm.obj \
+..\src\glpspx01.obj \
+..\src\glpspx02.obj \
+..\src\glpsql.obj \
+..\src\glpssx01.obj \
+..\src\glpssx02.obj \
+..\src\glptsp.obj \
+..\src\amd\amd_1.obj \
+..\src\amd\amd_2.obj \
+..\src\amd\amd_aat.obj \
+..\src\amd\amd_control.obj \
+..\src\amd\amd_defaults.obj \
+..\src\amd\amd_dump.obj \
+..\src\amd\amd_info.obj \
+..\src\amd\amd_order.obj \
+..\src\amd\amd_post_tree.obj \
+..\src\amd\amd_postorder.obj \
+..\src\amd\amd_preprocess.obj \
+..\src\amd\amd_valid.obj \
+..\src\colamd\colamd.obj \
+..\src\minisat\minisat.obj \
+..\src\zlib\adler32.obj \
+..\src\zlib\compress.obj \
+..\src\zlib\crc32.obj \
+..\src\zlib\deflate.obj \
+..\src\zlib\gzclose.obj \
+..\src\zlib\gzlib.obj \
+..\src\zlib\gzread.obj \
+..\src\zlib\gzwrite.obj \
+..\src\zlib\infback.obj \
+..\src\zlib\inffast.obj \
+..\src\zlib\inflate.obj \
+..\src\zlib\inftrees.obj \
+..\src\zlib\trees.obj \
+..\src\zlib\uncompr.obj \
+..\src\zlib\zio.obj \
+..\src\zlib\zutil.obj
+
+.c.obj:
+        cl.exe $(CFLAGS) /Fo$*.obj /c $*.c
+
+all: glpk_4_47.dll glpsol.exe
+
+glpk_4_47.dll: $(OBJSET)
+        cl.exe $(CFLAGS) /LD /Feglpk_4_47.dll \
+                ..\src\*.obj \
+                ..\src\amd\*.obj \
+                ..\src\colamd\*.obj \
+                ..\src\minisat\*.obj \
+                ..\src\zlib\*.obj \
+                glpk_4_47.def
+
+glpsol.exe: ..\examples\glpsol.obj glpk_4_47.dll
+        cl.exe $(CFLAGS) /Feglpsol.exe \
+                ..\examples\glpsol.obj glpk_4_47.lib
+
+check: glpsol.exe
+        .\glpsol.exe --version
+        .\glpsol.exe --mps ..\examples\plan.mps
+
+## eof ##
Index: deps/glpk/w64/readme.txt
===================================================================
--- deps/glpk/w64/readme.txt	(revision 9)
+++ deps/glpk/w64/readme.txt	(revision 9)
@@ -0,0 +1,24 @@
+This directory contains batch files and other stuff which you can use
+to build GLPK for 64-bit Windows with the native C/C++ compilers.
+
+Before running the batch file do the following:
+
+1. Make sure that you have installed the compiler you are going to use
+   to build GLPK.
+
+2. Look into corresponding batch file (just right-click it and choose
+   'Edit' in the popup menu; DO NOT choose 'Open'). Make sure that HOME
+   variable specifies correct path to the compiler directory; if not,
+   make necessary changes.
+
+To run the batch file just double-click it and wait a bit while the
+Make utility does its job. The message 'OPTIMAL SOLUTION FOUND' in the
+MS-DOS window means that all is OK. If you do not see it, something is
+wrong.
+
+Once GLPK has been successfully built, there must appear two files in
+this directory:
+
+glpk.lib, which is the GLPK object library, and
+
+glpsol.exe, which is the stand-alone GLPK LP/MIP solver.
